From f070fa3235e8b7e6a5e4d99e51b7f90c8b494fa7 Mon Sep 17 00:00:00 2001 From: Giuseppe Guerrini Date: Mon, 23 Sep 2024 14:43:28 +0200 Subject: [PATCH 1/5] Added experimental support for Level-2 tunnel (Tunnel=ethernet option) on Windows. It needs TAP-Windows driver. --- README-TAP-Tindows.txt | 37 +++ clientloop.c | 2 +- configure.ac | 1 + contrib/win32/openssh/config.h.vs | 3 + contrib/win32/win32compat/fileio.c | 169 +++++++------ contrib/win32/win32compat/inc/fcntl.h | 2 + misc.c | 4 +- misc.h | 2 +- openbsd-compat/port-net.c | 347 +++++++++++++++++++++++++- openbsd-compat/port-net.h | 4 +- readconf.c | 15 ++ readconf.h | 2 + servconf.c | 14 +- servconf.h | 2 + serverloop.c | 2 +- 15 files changed, 515 insertions(+), 91 deletions(-) create mode 100644 README-TAP-Tindows.txt diff --git a/README-TAP-Tindows.txt b/README-TAP-Tindows.txt new file mode 100644 index 000000000000..b165653e162e --- /dev/null +++ b/README-TAP-Tindows.txt @@ -0,0 +1,37 @@ + +Experimental tunnel management has been added on Windows. It relies on +TAP-Windows V9 driver, avilable here: + + https://build.openvpn.net/downloads/releases/tap-windows-9.23.3-I601-Win10.exe + +At the moment (2024/09/23) this patch has been tested only on Windows10-19045 +and TAP-Windows driver 9.23.3.601. Most of the tests used client mode +(ssh.exe). Server mode (sshd.exe) has only been tested superficially. + +Since TAP driver only supports level-2 tunnel, option "Tunnel=ethernet" must +be provided by "-o" command line option or by configuration file. + +A notable difference between Linux TAP and Windows TAP is that on Windows +there is no dynamic TAP device instance creation. This is why we need to +statically create a number of TAP adapter instances by installing TAP driver +for the desired number of times. Each adapter created this way must be +renamed manually, the names must begin with a common prefix ("SSH Tunnel" by +default). SSH will search a free adapter into the set of adapters whose name +begins with the prefix. The number of adapters created in this way is the number +of simultaneous sessions that can be opened. For clients (ssh.exe) one +single instance is usually enough, but for servers (sshd.exe) a largest number +of reserved adapters is required. The name prefix SSH looks for can be +configured by setting the new option "TunnelOptions". At the moment, only +ASCII characters are allowed, although Windows uses WCHAR for adapter names +(property "FriendlyName"). + +It is advised to specify "-w any" in command line, and let the program +choose a free adapter. Although it is possible to specify a particular tunnel +device number (the "IfIndex" adapter's property), it isn't handy to get it, +since Windows puts al kind of adapters (TAP, ethernet...) togather, and +enumeration is not intuitive. A way to get it is the powershell command +"Get-NetAdapter". + +SSH only establishes the L2 tunnel, it is on the user (both on the client and the +server side) to configure the TAP device (IP addresses, gateway, routes..). + diff --git a/clientloop.c b/clientloop.c index 3942324613fd..b7816a21bdf1 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1866,7 +1866,7 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode, debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); /* Open local tunnel device */ - if ((fd = tun_open(local_tun, tun_mode, &ifname)) == -1) { + if ((fd = tun_open(local_tun, tun_mode, options.tunnel_options, &ifname)) == -1) { error("Tunnel device open failed."); return NULL; } diff --git a/configure.ac b/configure.ac index d8816e3f65de..bc60ed0ae87e 100644 --- a/configure.ac +++ b/configure.ac @@ -758,6 +758,7 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) AC_DEFINE_UNQUOTED([BIND_8_COMPAT], [1], [Define if your resolver libs need this for getrrsetbyname]) AC_DEFINE([SSH_TUN_FREEBSD], [1], [Open tunnel devices the FreeBSD way]) + AC_DEFINE([SSH_TUN_TAP_WINDOWS_V9], [1], [Use TAP-Windows Adapter V9 (>=W10 only)]) AC_DEFINE([SSH_TUN_COMPAT_AF], [1], [Use tunnel device compatibility to OpenBSD]) AC_DEFINE([SSH_TUN_PREPEND_AF], [1], diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index d19b10758627..73a2593d9ee6 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1474,6 +1474,9 @@ /* Open tunnel devices the FreeBSD way */ /* #undef SSH_TUN_FREEBSD */ +/* Use TAP-Windows Adapter V9 (>=W10 only) */ +#define SSH_TUN_TAP_WINDOWS_V9 1 + /* Open tunnel devices the Linux tun/tap way */ /* #undef SSH_TUN_LINUX */ diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index b7e4e6338274..4b14873e456f 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -317,7 +317,7 @@ createFile_flags_setup(int flags, mode_t mode, struct createFile_flags* cf_flags } /*only following create and status flags currently supported*/ - if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_BINARY)) { + if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_BINARY | O_SYSTEM)) { debug3("open - ERROR: Unsupported flags: %d", flags); errno = ENOTSUP; return -1; @@ -354,7 +354,14 @@ createFile_flags_setup(int flags, mode_t mode, struct createFile_flags* cf_flags if (c_s_flags & O_APPEND) cf_flags->dwDesiredAccess = FILE_APPEND_DATA; - cf_flags->dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS; + // Hack to deal with TAP driver requirements: FILE_ATTRIBUTE_SYSTEM, no FILE_FLAG_BACKUP_SEMANTICS + if (c_s_flags & O_SYSTEM) { + cf_flags->dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_SYSTEM; + mode = USHRT_MAX; + } + else { + cf_flags->dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS; + } // If the mode is USHRT_MAX then we will inherit the permissions from the parent folder. if (mode != USHRT_MAX) { @@ -427,12 +434,12 @@ file_in_chroot_jail(HANDLE handle) { if (!final_path) return 0; - const wchar_t* uncPrefix = L"UNC\\"; - int isUNCPath = memcmp(final_path, uncPrefix, 2 * wcslen(uncPrefix)); - - if (0 == isUNCPath) { - debug3("symlink points to UNCPath"); - return 1; + const wchar_t* uncPrefix = L"UNC\\"; + int isUNCPath = memcmp(final_path, uncPrefix, 2 * wcslen(uncPrefix)); + + if (0 == isUNCPath) { + debug3("symlink points to UNCPath"); + return 1; } to_wlower_case(final_path); @@ -682,35 +689,35 @@ WriteCompletionRoutine(_In_ DWORD dwErrorCode, *((__int64*)&lpOverlapped->Offset) += dwNumberOfBytesTransfered; } -int -fileio_write_wrapper(struct w32_io* pio, const void* buf, size_t bytes_to_copy) -{ - int bytes_written = 0; - if (bytes_to_copy <= WRITE_BUFFER_SIZE) { - bytes_written = fileio_write(pio, buf, bytes_to_copy); - return bytes_written; - } - - void* chunk_buf = NULL; - int chunk_count = 0; - int bytes_copied = -1; - size_t chunk_size = 0; - - for (int i = 0; i < bytes_to_copy; i += WRITE_BUFFER_SIZE, chunk_count++) { - chunk_buf = (BYTE*)buf + chunk_count * WRITE_BUFFER_SIZE; - chunk_size = ((bytes_to_copy - i) >= WRITE_BUFFER_SIZE) ? WRITE_BUFFER_SIZE : (bytes_to_copy - i); - bytes_written = fileio_write(pio, chunk_buf, chunk_size); - - if (bytes_written == -1) - return bytes_copied; - - if (bytes_copied == -1) - bytes_copied = 0; - - bytes_copied += bytes_written; - } - return bytes_copied; - +int +fileio_write_wrapper(struct w32_io* pio, const void* buf, size_t bytes_to_copy) +{ + int bytes_written = 0; + if (bytes_to_copy <= WRITE_BUFFER_SIZE) { + bytes_written = fileio_write(pio, buf, bytes_to_copy); + return bytes_written; + } + + void* chunk_buf = NULL; + int chunk_count = 0; + int bytes_copied = -1; + size_t chunk_size = 0; + + for (int i = 0; i < bytes_to_copy; i += WRITE_BUFFER_SIZE, chunk_count++) { + chunk_buf = (BYTE*)buf + chunk_count * WRITE_BUFFER_SIZE; + chunk_size = ((bytes_to_copy - i) >= WRITE_BUFFER_SIZE) ? WRITE_BUFFER_SIZE : (bytes_to_copy - i); + bytes_written = fileio_write(pio, chunk_buf, chunk_size); + + if (bytes_written == -1) + return bytes_copied; + + if (bytes_copied == -1) + bytes_copied = 0; + + bytes_copied += bytes_written; + } + return bytes_copied; + } /* write() implementation */ @@ -947,51 +954,51 @@ fileio_lseek(struct w32_io* pio, unsigned __int64 offset, int origin) return 0; } -/* fdopen() to be used on pipe handles */ -static FILE* -fileio_fdopen_pipe(struct w32_io* pio, const char *mode) -{ - int fd_flags = 0; - FILE* ret; - debug4("fdopen - io:%p", pio); - - if (mode[1] == '\0') { - switch (*mode) { - case 'r': - fd_flags = _O_RDONLY; - break; - case 'w': - break; - case 'a': - fd_flags = _O_APPEND; - break; - default: - errno = ENOTSUP; - debug3("fdopen - ERROR unsupported mode %s", mode); - return NULL; - } - } - else { - errno = ENOTSUP; - debug3("fdopen - ERROR unsupported mode %s", mode); - return NULL; - } - - int fd = _open_osfhandle((intptr_t)pio->handle, fd_flags); - - if (fd == -1 || (ret = _fdopen(fd, mode)) == NULL) { - errno = EOTHER; - debug3("fdopen - ERROR:%d _open_osfhandle()", errno); - return NULL; - } - - // overwrite underlying win32 handle - its expected to be closed via fclose - // and close pio - pio->handle = NULL; +/* fdopen() to be used on pipe handles */ +static FILE* +fileio_fdopen_pipe(struct w32_io* pio, const char *mode) +{ + int fd_flags = 0; + FILE* ret; + debug4("fdopen - io:%p", pio); + + if (mode[1] == '\0') { + switch (*mode) { + case 'r': + fd_flags = _O_RDONLY; + break; + case 'w': + break; + case 'a': + fd_flags = _O_APPEND; + break; + default: + errno = ENOTSUP; + debug3("fdopen - ERROR unsupported mode %s", mode); + return NULL; + } + } + else { + errno = ENOTSUP; + debug3("fdopen - ERROR unsupported mode %s", mode); + return NULL; + } + + int fd = _open_osfhandle((intptr_t)pio->handle, fd_flags); + + if (fd == -1 || (ret = _fdopen(fd, mode)) == NULL) { + errno = EOTHER; + debug3("fdopen - ERROR:%d _open_osfhandle()", errno); + return NULL; + } + + // overwrite underlying win32 handle - its expected to be closed via fclose + // and close pio + pio->handle = NULL; int w32_close(int); - w32_close(pio->table_index); - return ret; -} + w32_close(pio->table_index); + return ret; +} /* fdopen() to be used on file handles */ static FILE* diff --git a/contrib/win32/win32compat/inc/fcntl.h b/contrib/win32/win32compat/inc/fcntl.h index 94ed0fa3dfe3..c522f67d0c21 100644 --- a/contrib/win32/win32compat/inc/fcntl.h +++ b/contrib/win32/win32compat/inc/fcntl.h @@ -37,6 +37,8 @@ void* w32_fd_to_handle(int fd); #define O_SEQUENTIAL _O_SEQUENTIAL #define O_RANDOM _O_RANDOM #define O_U16TEXT _O_U16TEXT +// Hack to deal with TAP driver requirements: FILE_ATTRIBUTE_SYSTEM, no FILE_FLAG_BACKUP_SEMANTICS +#define O_SYSTEM 0x4000000 /* * open() POSIX specific modes and flags. diff --git a/misc.c b/misc.c index 40aa05a9d2f1..5749f3444d01 100644 --- a/misc.c +++ b/misc.c @@ -1476,10 +1476,10 @@ percent_dollar_expand(const char *string, ...) } int -tun_open(int tun, int mode, char **ifname) +tun_open(int tun, int mode, const char* tunnel_options, char **ifname) { #if defined(CUSTOM_SYS_TUN_OPEN) - return (sys_tun_open(tun, mode, ifname)); + return (sys_tun_open(tun, mode, tunnel_options, ifname)); #elif defined(SSH_TUN_OPENBSD) struct ifreq ifr; char name[100]; diff --git a/misc.h b/misc.h index 151564e6f509..ad93877380de 100644 --- a/misc.h +++ b/misc.h @@ -129,7 +129,7 @@ void freeargs(arglist *); void duplicateargs(arglist *, const arglist *); #endif -int tun_open(int, int, char **); +int tun_open(int, int, const char *, char **); /* Common definitions for ssh tunnel device forwarding */ #define SSH_TUNMODE_NO 0x00 diff --git a/openbsd-compat/port-net.c b/openbsd-compat/port-net.c index 198e73f0de20..64db19ea497c 100644 --- a/openbsd-compat/port-net.c +++ b/openbsd-compat/port-net.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" #include "includes.h" #include @@ -141,7 +142,7 @@ sys_set_process_rdomain(const char *name) #define TUN_CTRL_DEV "/dev/net/tun" int -sys_tun_open(int tun, int mode, char **ifname) +sys_tun_open(int tun, int mode, const char* tunnel_options, char **ifname) { struct ifreq ifr; int fd = -1; @@ -206,7 +207,7 @@ sys_tun_open(int tun, int mode, char **ifname) #endif int -sys_tun_open(int tun, int mode, char **ifname) +sys_tun_open(int tun, int mode, const char* tunnel_options, char **ifname) { struct ifreq ifr; char name[100]; @@ -376,3 +377,345 @@ sys_tun_outfilter(struct ssh *ssh, struct Channel *c, return (buf); } #endif /* SSH_TUN_FILTER */ + +#if defined(SSH_TUN_TAP_WINDOWS_V9) + +#if defined(WIN32) || defined(WIN64) + +//////////////////////////////////////////////////////////////////// +// +// Experimental support for Windows Tunnel (TAP-Windows V9 driver) +// +// This part adds a quite rude support to tunnel device on Windows, +// so you can use "-w" options on Windows. +// It uses TAP-Windows V9 driver. At the moment (2024/09/20) this +// code has been tested only on Windows10-19045 and TAP-Windows +// driver 9.23.3.601 (you can download it here: +// https://build.openvpn.net/downloads/releases/tap-windows-9.23.3-I601-Win10.exe). +// Only "ethernet" tunnel mode is supported, since TAP-Windows +// driver doesn't implement TUN (point-to-point). Because of this, +// "-o Tunnel=ethernet" command line option or equivalent configuration +// item must be set. Here's the typical command invocation: +// +// ssh -o Tunnel=ethernet user@host -w any +// +// One can also specify an adapter index (the ifIndex field +// as shown, for example, in powershell's "get-netadapter" +// output) to force the use of a particular TAP instance. +// +// Here's what the function "sys_tun_open" does: +// - It checks if the selected tunnel mode is "ethernet". +// - It explores the list of adapters returned by +// GetAdaptersAddresses Windows function (from IPHLPAPI subsystem). +// - If a index is specified, the function takes the adaper +// whose IfIndex match the given value. If the index is not +// specified ("any"), the function takes the adapters whose +// friendly name starts with "SSH Tunnel" (case insensitive) +// or whatever is configured (see "TunnelOptions" configuration +// item). +// - If a matching adapter if found, the function tries to open +// and activate it. In case of failure, it takes the next matching +// adapter. +// - The file descriptor of the first successful open is resturned, +// or -1 if there are no free adapters. +// +// The function relies on the presence of a certain number of +// instances of the TAP-Windows driver, all with friendly names +// starting with "SSH Tunnel". During installation, these instances +// must be generated by installing the driver as many times as +// necessary. Each instance must be renamed according to the +// convention (e.g. "SSH Tunnel 1", "SSH Tunnel 2" ...). +// You can change the default prefix via "TunnelOptions" +// configuration item. NOTE: Only ANSI characters are allowed. +// +// NOTE: TAP devices must be opened in a special way. In order to +// make the device interoperate with the existing SSH framework +// (based on UNIX' "file descriptor" paradigm), we added +// a special flag "O_SYSTEM" for "open". This is because the way +// "open" ("w32_open") calls "CreateFile" is not suitable for TAP +// devices. In particular, FILE_ATTRIBUTE_SYSTEM must be provided, +// and FILE_FLAG_BACKUP_SEMANTICS must not appear. The new flag +// instructs "open" to respect this rule. +// +//////////////////////////////////////////////////////////////////// + +#include +#include + +#pragma comment(lib, "IPHLPAPI.lib") + +#include "ssh.h" + +//#include "readconf.h" +//extern Options options; + +/* From OpenVPN tap driver, common.h */ +#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE (10, METHOD_BUFFERED) + + +#define SSH_BASE_ADAPTER_FRIENDLY_NAME "SSH Tunnel" + +static int open_adapter(const char* name) +{ + int fd = -1; + char *netdev = NULL; + int ok = 0; + + debug(" Trying adapter %s", name); + + + netdev = (char*)malloc(strlen(name) + 30 /* 16 at least */); + if (netdev == NULL) { + error("Out of memory while creating adapter device name"); + goto FAIL; + } + + sprintf(netdev, "\\\\.\\Global\\%s.tap", name); + + /* + HANDLE h = CreateFile(netdev, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + */ + + // Open device. Non-standard flag O_SYSTEM forces FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED + // in CreateFile. + // NOTE: "open" internally modifies paths (e.g. converts "\" in "/" + // and much more). Windows seems to understand anyway, fortunately. + + fd = open(netdev, O_RDWR | O_EXCL | O_SYSTEM); + + if (fd < 0) { + goto FAIL; + } + + HANDLE h = w32_fd_to_handle(fd); + DWORD len = 0; + + // For debugging purpose, we print the MAC. + // It is also a way to make sure that the device is a TAP. + + unsigned char mac[6]; + + if (DeviceIoControl(h, TAP_IOCTL_GET_MAC, &mac, sizeof(mac), &mac, sizeof(mac), &len, NULL)) { + debug(" Adapter's MAC: %02x-%02x-%02x-%02x-%02x-%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + else { + // We could survive (we don't actually need to know MAC), + // but a failure here is a symptom of more general + // problems, or perhaps the device is not a real TAP, but something else. + error("Could not get adapter MAC, error 0x%08x", GetLastError()); + goto FAIL; + } + + // Turn adapter on. If we didn't do the device couldn't work (e.g. ReadFileEx would fail). + + ULONG flag = 1; + + if (DeviceIoControl(h, TAP_IOCTL_SET_MEDIA_STATUS, &flag, sizeof(flag), &flag, sizeof(flag), &len, NULL) == 0) { + error("Could not activate adapter, error 0x%08x", GetLastError()); + goto FAIL; + } + + ok = 1; + +FAIL: + if (!ok) { + if (fd >= 0) { + close(fd); + fd = -1; + } + } + if (netdev != NULL) { + free(netdev); + } + return fd; +} + +static int lookup_and_open_tap_instance(int tun, char** ifname, const char *prefix) +{ + DWORD rv; + ULONG sz = 0; + ULONG new_sz = 0x4000; + PIP_ADAPTER_ADDRESSES result = NULL; + int tun_fd = -1; + PWCHAR match = NULL; + size_t match_len = 0; + int ok = 0; + + if (prefix == NULL) { + prefix = SSH_BASE_ADAPTER_FRIENDLY_NAME; + } + + match_len = mbstowcs(NULL, prefix, 0); + if (match_len == (size_t)(-1)) { + error("Bad adapter name prefix: \"%s\"", prefix); + goto FAIL; + } + match = (PWCHAR)malloc((match_len + 1) * sizeof(*match)); + if (match == NULL) { + error("Out of memory while creating adapter name"); + goto FAIL; + } + match_len = mbstowcs(match, prefix, match_len + 1); + + // if tun == SSH_TUNID_ANY: + // Looking for a free TUN/TAP instance. + // We should create some TUN/TAP instances devoted to SSH, + // and choose a recognizable "frendly name" for them, + // otherwise whe could disturb (or be distubed by) + // other applications (e.g. OpenVPN). + // So, we'll look for the first free adapter whose frendly name + // starts with "SSH Tunnel" (or whatever is configured). + // TODO: Add a configuration item to change the string. + // if tun != SSH_TUNID_ANY: + // We got an adapter IfIndex directly from options, we have just + // to check if it's a TUN/TAP instance. + // + // Anyway, we explore the list of IP_ADAPTER_ADDRESSES objects + // and try to open the device instance of first one whose + // FiendlyName or IfIndex match. If the device is busy or not working, + // we try the next objects. + // + + + if (tun != SSH_TUNID_ANY) { + debug("Exploring network adapter list, looking for IfIndex %d", tun); + } + else { + debug("Exploring network adapter list, looking for a FriendlyName matching \"%ws.*\"", match); + } + + for (;;) { + if (sz < new_sz) { + if (result != NULL) { + free(result); + } + sz = new_sz; + result = (PIP_ADAPTER_ADDRESSES)malloc(sz); + if (result == NULL) { + error("Out of memory while reading adapter list"); + goto FAIL; + } + } + rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_INCLUDE_PREFIX, NULL, result, &new_sz); + if (rv == ERROR_SUCCESS) { + break; + } + if (rv != ERROR_BUFFER_OVERFLOW) { + error("Could not read adapter list, error 0x%08x", (unsigned int)rv); + goto FAIL; + } + } + + PIP_ADAPTER_ADDRESSES addr; + int no_match = 1; + + for (addr = result; addr != NULL; addr = addr->Next) { + + int match_found = 0; + + debug3(" Adapter %lu: Name=\"%s\", FriendlyName=\"%ws\", Description=\"%ws\"", addr->IfIndex, addr->AdapterName, addr->FriendlyName, addr->Description); + + if (tun != SSH_TUNID_ANY) { + if (addr->IfIndex == (IF_INDEX)tun) { + match_found = 1; + } + } + else { + if (_wcsnicmp(addr->FriendlyName, match, match_len) == 0) { + match_found = 1; + } + } + + if (match_found) { + + no_match = 0; + + tun_fd = open_adapter(addr->AdapterName); + + if (tun_fd >= 0 || tun != SSH_TUNID_ANY) { + break; + } + } + } + + if (no_match) { + debug("No matching adapter found"); + } + + if (tun_fd != -1 && ifname != NULL) { + *ifname = strdup(addr->AdapterName); + if (*ifname == NULL) { + error("Out of memory while storing adapter name"); + goto FAIL; + } + } + + ok = 1; + +FAIL: + + if (match != NULL) { + free(match); + } + + if (result != NULL) { + free(result); + } + + if (!ok) { + if (ifname != NULL && *ifname != NULL) { + free(*ifname); + } + if (tun_fd != -1) { + close(tun_fd); + tun_fd = -1; + } + } + + return tun_fd; +} + +int +sys_tun_open(int tun, int mode, const char *tunnel_options, char** ifname) +{ + int tun_fd = -1; + const char *prefix = NULL; + + prefix = tunnel_options; + + if (ifname != NULL) { + *ifname = NULL; + } + + if (mode != SSH_TUNMODE_ETHERNET) { + // Sorry, TUN/TAP for Windows is actually TAP only. + // TODO: Simulate Point-to-point (== TUN) + error("Only ethernet mode tunnel interfaces (a.k.a. TAP) are supported on this platform"); + goto FAIL; + } + + tun_fd = lookup_and_open_tap_instance(tun, ifname, prefix); + +FAIL: + return tun_fd; +} + +#else + +#error SSH_TUN_TAP_WINDOWS_V9 option is valid only on Windows + +#endif + +#endif // SSH_TUN_TAP_WINDOWS_V9 + diff --git a/openbsd-compat/port-net.h b/openbsd-compat/port-net.h index 3a0d1104bf6d..64f820e52a9f 100644 --- a/openbsd-compat/port-net.h +++ b/openbsd-compat/port-net.h @@ -20,9 +20,9 @@ struct Channel; struct ssh; -#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD) +#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD) || defined(SSH_TUN_TAP_WINDOWS_V9) # define CUSTOM_SYS_TUN_OPEN -int sys_tun_open(int, int, char **); +int sys_tun_open(int, int, const char *, char **); #endif #if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF) diff --git a/readconf.c b/readconf.c index 34b7fa69b799..e4aa9c4244c8 100644 --- a/readconf.c +++ b/readconf.c @@ -180,6 +180,7 @@ typedef enum { oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, oEnableEscapeCommandline, oObscureKeystrokeTiming, + oTunnelOptions, oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -329,6 +330,7 @@ static struct { { "requiredrsasize", oRequiredRSASize }, { "enableescapecommandline", oEnableEscapeCommandline }, { "obscurekeystroketiming", oObscureKeystrokeTiming }, + { "tunneloptions", oTunnelOptions }, { NULL, oBadOption } }; @@ -2346,6 +2348,13 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, argv_consume(&ac); break; + case oTunnelOptions: + charptr = &options->tunnel_options; + arg = argv_next(&ac, &av); + if (*activep && *charptr == NULL) + *charptr = xstrdup((arg == NULL) ? "" : arg); + break; + default: error("%s line %d: Unimplemented opcode %d", filename, linenum, opcode); @@ -2596,6 +2605,7 @@ initialize_options(Options * options) options->required_rsa_size = -1; options->enable_escape_commandline = -1; options->obscure_keystroke_timing_interval = -1; + options->tunnel_options = NULL; options->tag = NULL; } @@ -2849,6 +2859,8 @@ fill_default_options(Options * options) CLEAR_ON_NONE(options->pkcs11_provider); CLEAR_ON_NONE(options->sk_provider); CLEAR_ON_NONE(options->known_hosts_command); + CLEAR_ON_NONE(options->tunnel_options); + if (options->jump_host != NULL && strcmp(options->jump_host, "none") == 0 && options->jump_port == 0 && options->jump_user == NULL) { @@ -3596,6 +3608,9 @@ dump_client_config(Options *o, const char *host) printf(":%d", o->tun_remote); printf("\n"); + dump_cfg_string(oTunnelOptions, o->tunnel_options); + + /* oCanonicalizePermittedCNAMEs */ printf("canonicalizePermittedcnames"); if (o->num_permitted_cnames == 0) diff --git a/readconf.h b/readconf.h index ce261bd63642..f7dd1b1de22a 100644 --- a/readconf.h +++ b/readconf.h @@ -182,6 +182,8 @@ typedef struct { int enable_escape_commandline; /* ~C commandline */ int obscure_keystroke_timing_interval; + char *tunnel_options; + char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ } Options; diff --git a/servconf.c b/servconf.c index 1ee4e27d9bb3..1119a1afc362 100644 --- a/servconf.c +++ b/servconf.c @@ -175,6 +175,7 @@ initialize_server_options(ServerOptions *options) options->num_accept_env = 0; options->num_setenv = 0; options->permit_tun = -1; + options->tunnel_options = NULL; options->permitted_opens = NULL; options->permitted_listens = NULL; options->adm_forced_command = NULL; @@ -484,6 +485,7 @@ fill_default_server_options(ServerOptions *options) CLEAR_ON_NONE(options->chroot_directory); CLEAR_ON_NONE(options->routing_domain); CLEAR_ON_NONE(options->host_key_agent); + CLEAR_ON_NONE(options->tunnel_options); for (i = 0; i < options->num_host_key_files; i++) CLEAR_ON_NONE(options->host_key_files[i]); @@ -520,7 +522,7 @@ typedef enum { sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, - sAcceptEnv, sSetEnv, sPermitTunnel, + sAcceptEnv, sSetEnv, sPermitTunnel, sTunnelOptions, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sHostCertificate, sInclude, @@ -663,6 +665,7 @@ static struct { { "acceptenv", sAcceptEnv, SSHCFG_ALL }, { "setenv", sSetEnv, SSHCFG_ALL }, { "permittunnel", sPermitTunnel, SSHCFG_ALL }, + { "tunneloptions", sTunnelOptions, SSHCFG_GLOBAL }, { "permittty", sPermitTTY, SSHCFG_ALL }, { "permituserrc", sPermitUserRC, SSHCFG_ALL }, { "match", sMatch, SSHCFG_ALL }, @@ -2162,6 +2165,14 @@ process_server_config_line_depth(ServerOptions *options, char *line, *intptr = value; break; + case sTunnelOptions: + charptr = &options->tunnel_options; + arg = argv_next(&ac, &av); + if (*activep && *charptr == NULL) + *charptr = xstrdup((arg == NULL) ? "" : arg); + break; + + case sInclude: if (cmdline) { fatal("Include directive not supported as a " @@ -3259,6 +3270,7 @@ dump_config(ServerOptions *o) } } dump_cfg_string(sPermitTunnel, s); + dump_cfg_string(sTunnelOptions, o->tunnel_options); printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); printf("%s\n", iptos2str(o->ip_qos_bulk)); diff --git a/servconf.h b/servconf.h index ed7b72e8e0e3..b8fe50387099 100644 --- a/servconf.h +++ b/servconf.h @@ -201,6 +201,8 @@ typedef struct { int permit_tun; + char* tunnel_options; + char **permitted_opens; /* May also be one of PERMITOPEN_* */ u_int num_permitted_opens; char **permitted_listens; /* May also be one of PERMITOPEN_* */ diff --git a/serverloop.c b/serverloop.c index f3683c2e4a6d..261df79b8cfd 100644 --- a/serverloop.c +++ b/serverloop.c @@ -549,7 +549,7 @@ server_request_tun(struct ssh *ssh) goto done; tun = auth_opts->force_tun_device; } - sock = tun_open(tun, mode, &ifname); + sock = tun_open(tun, mode, options.adm_forced_command, &ifname); if (sock < 0) goto done; debug("Tunnel forwarding using interface %s", ifname); From 6e77f3a552fcb03b364faf35597e26768a99e848 Mon Sep 17 00:00:00 2001 From: giusguerrini <61160697+giusguerrini@users.noreply.github.com> Date: Mon, 23 Sep 2024 19:17:05 +0200 Subject: [PATCH 2/5] Update and rename README-TAP-Tindows.txt to README-TAP-Windows.txt --- README-TAP-Tindows.txt => README-TAP-Windows.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename README-TAP-Tindows.txt => README-TAP-Windows.txt (94%) diff --git a/README-TAP-Tindows.txt b/README-TAP-Windows.txt similarity index 94% rename from README-TAP-Tindows.txt rename to README-TAP-Windows.txt index b165653e162e..dd69b2ebe171 100644 --- a/README-TAP-Tindows.txt +++ b/README-TAP-Windows.txt @@ -1,5 +1,5 @@ -Experimental tunnel management has been added on Windows. It relies on +Experimental tunnel management has been added on Windows. It relies on TAP-Windows V9 driver, avilable here: https://build.openvpn.net/downloads/releases/tap-windows-9.23.3-I601-Win10.exe From 05d0b016833456b6bcc2c9cae0cfc45313d4cf55 Mon Sep 17 00:00:00 2001 From: giusguerrini <61160697+giusguerrini@users.noreply.github.com> Date: Tue, 24 Sep 2024 00:02:49 +0200 Subject: [PATCH 3/5] Update serverloop.c --- serverloop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serverloop.c b/serverloop.c index 2b0f33d4119b..86932e2ad16f 100644 --- a/serverloop.c +++ b/serverloop.c @@ -516,7 +516,7 @@ server_request_tun(struct ssh *ssh) goto done; tun = auth_opts->force_tun_device; } - sock = tun_open(tun, mode, options.adm_forced_command, &ifname); + sock = tun_open(tun, mode, options.tunnel_options, &ifname); if (sock < 0) goto done; debug("Tunnel forwarding using interface %s", ifname); From ad8b4217d5e5650f1ff180fbcfe83afb335f7b60 Mon Sep 17 00:00:00 2001 From: Giuseppe Guerrini Date: Tue, 1 Oct 2024 00:09:21 +0200 Subject: [PATCH 4/5] Removed "TunnelOptions" option. Its function is now fulfilled by "PermitTunnel"(sshd) and "Tunnel" (ssh): you can append to the type of tunnel a ":" followed by options (e.g. Tunnel=ethernet:my_option) --- clientloop.c | 2 +- misc.c | 4 ++-- openbsd-compat/port-net.c | 4 ++-- readconf.c | 20 ++++++-------------- readconf.h | 2 +- servconf.c | 29 ++++++++++++++--------------- servconf.h | 2 +- serverloop.c | 2 +- 8 files changed, 28 insertions(+), 37 deletions(-) diff --git a/clientloop.c b/clientloop.c index cc31c3e4e1c5..608cf20fa7ab 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1861,7 +1861,7 @@ client_request_tun_fwd(struct ssh *ssh, int tun_mode, debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); /* Open local tunnel device */ - if ((fd = tun_open(local_tun, tun_mode, options.tunnel_options, &ifname)) == -1) { + if ((fd = tun_open(local_tun, tun_mode, options.tun_options, &ifname)) == -1) { error("Tunnel device open failed."); return NULL; } diff --git a/misc.c b/misc.c index 3916de8792a4..3eb27cf3d8b2 100644 --- a/misc.c +++ b/misc.c @@ -1492,10 +1492,10 @@ percent_dollar_expand(const char *string, ...) } int -tun_open(int tun, int mode, const char* tunnel_options, char **ifname) +tun_open(int tun, int mode, const char* tun_options, char **ifname) { #if defined(CUSTOM_SYS_TUN_OPEN) - return (sys_tun_open(tun, mode, tunnel_options, ifname)); + return (sys_tun_open(tun, mode, tun_options, ifname)); #elif defined(SSH_TUN_OPENBSD) struct ifreq ifr; char name[100]; diff --git a/openbsd-compat/port-net.c b/openbsd-compat/port-net.c index 64db19ea497c..58b24749c9f4 100644 --- a/openbsd-compat/port-net.c +++ b/openbsd-compat/port-net.c @@ -687,12 +687,12 @@ static int lookup_and_open_tap_instance(int tun, char** ifname, const char *pref } int -sys_tun_open(int tun, int mode, const char *tunnel_options, char** ifname) +sys_tun_open(int tun, int mode, const char *tun_options, char** ifname) { int tun_fd = -1; const char *prefix = NULL; - prefix = tunnel_options; + prefix = tun_options; if (ifname != NULL) { *ifname = NULL; diff --git a/readconf.c b/readconf.c index 2467e737e7b3..c231e3bc2c6e 100644 --- a/readconf.c +++ b/readconf.c @@ -180,7 +180,6 @@ typedef enum { oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout, - oTunnelOptions, oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -331,7 +330,6 @@ static struct { { "enableescapecommandline", oEnableEscapeCommandline }, { "obscurekeystroketiming", oObscureKeystrokeTiming }, { "channeltimeout", oChannelTimeout }, - { "tunneloptions", oTunnelOptions }, { NULL, oBadOption } }; @@ -1185,6 +1183,7 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, multistate_ptr = multistate_flag; parse_multistate: arg = argv_next(&ac, &av); + parse_multistate_arg: if ((value = parse_multistate_value(arg, filename, linenum, multistate_ptr)) == -1) { error("%s line %d: unsupported option \"%s\".", @@ -1949,7 +1948,8 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, case oTunnel: intptr = &options->tun_open; multistate_ptr = multistate_tunnel; - goto parse_multistate; + arg = argv_next(&ac, &av); + goto parse_multistate_arg; case oTunnelDevice: arg = argv_next(&ac, &av); @@ -2413,13 +2413,6 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, argv_consume(&ac); break; - case oTunnelOptions: - charptr = &options->tunnel_options; - arg = argv_next(&ac, &av); - if (*activep && *charptr == NULL) - *charptr = xstrdup((arg == NULL) ? "" : arg); - break; - default: error("%s line %d: Unimplemented opcode %d", filename, linenum, opcode); @@ -2672,7 +2665,7 @@ initialize_options(Options * options) options->required_rsa_size = -1; options->enable_escape_commandline = -1; options->obscure_keystroke_timing_interval = -1; - options->tunnel_options = NULL; + options->tun_options = NULL; options->tag = NULL; options->channel_timeouts = NULL; options->num_channel_timeouts = 0; @@ -2837,6 +2830,8 @@ fill_default_options(Options * options) options->hash_known_hosts = 0; if (options->tun_open == -1) options->tun_open = SSH_TUNMODE_NO; + if (options->tun_options == NULL) + options->tun_options = xstrdup(""); if (options->tun_local == -1) options->tun_local = SSH_TUNID_ANY; if (options->tun_remote == -1) @@ -2940,7 +2935,6 @@ fill_default_options(Options * options) CLEAR_ON_NONE(options->pkcs11_provider); CLEAR_ON_NONE(options->sk_provider); CLEAR_ON_NONE(options->known_hosts_command); - CLEAR_ON_NONE(options->tunnel_options); CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none"); #undef CLEAR_ON_NONE #undef CLEAR_ON_NONE_ARRAY @@ -3693,8 +3687,6 @@ dump_client_config(Options *o, const char *host) printf(":%d", o->tun_remote); printf("\n"); - dump_cfg_string(oTunnelOptions, o->tunnel_options); - /* oCanonicalizePermittedCNAMEs */ printf("canonicalizePermittedcnames"); diff --git a/readconf.h b/readconf.h index 9d6e09692b9a..ca22d03cb31a 100644 --- a/readconf.h +++ b/readconf.h @@ -184,7 +184,7 @@ typedef struct { char **channel_timeouts; /* inactivity timeout by channel type */ u_int num_channel_timeouts; - char *tunnel_options; + char *tun_options; char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ } Options; diff --git a/servconf.c b/servconf.c index 216c81c84584..d98fa86e7b1d 100644 --- a/servconf.c +++ b/servconf.c @@ -194,7 +194,7 @@ initialize_server_options(ServerOptions *options) options->num_accept_env = 0; options->num_setenv = 0; options->permit_tun = -1; - options->tunnel_options = NULL; + options->tun_options = NULL; options->permitted_opens = NULL; options->permitted_listens = NULL; options->adm_forced_command = NULL; @@ -472,6 +472,8 @@ fill_default_server_options(ServerOptions *options) } if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; + if (options->tun_options == NULL) + options->tun_options = xstrdup(""); if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_DSCP_AF21; if (options->ip_qos_bulk == -1) @@ -531,7 +533,6 @@ fill_default_server_options(ServerOptions *options) CLEAR_ON_NONE(options->chroot_directory); CLEAR_ON_NONE(options->routing_domain); CLEAR_ON_NONE(options->host_key_agent); - CLEAR_ON_NONE(options->tunnel_options); CLEAR_ON_NONE(options->per_source_penalty_exempt); for (i = 0; i < options->num_host_key_files; i++) @@ -570,7 +571,7 @@ typedef enum { sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, - sAcceptEnv, sSetEnv, sPermitTunnel, sTunnelOptions, + sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sHostCertificate, sInclude, @@ -718,7 +719,6 @@ static struct { { "acceptenv", sAcceptEnv, SSHCFG_ALL }, { "setenv", sSetEnv, SSHCFG_ALL }, { "permittunnel", sPermitTunnel, SSHCFG_ALL }, - { "tunneloptions", sTunnelOptions, SSHCFG_GLOBAL }, { "permittty", sPermitTTY, SSHCFG_ALL }, { "permituserrc", sPermitUserRC, SSHCFG_ALL }, { "match", sMatch, SSHCFG_ALL }, @@ -2292,9 +2292,17 @@ process_server_config_line_depth(ServerOptions *options, char *line, case sPermitTunnel: intptr = &options->permit_tun; arg = argv_next(&ac, &av); - if (!arg || *arg == '\0') + if (!arg || *arg == '\0') { fatal("%s line %d: %s missing argument.", - filename, linenum, keyword); + filename, linenum, keyword); + } + else { + char* opt = strchr(arg, ':'); + if (opt != NULL) { + options->tun_options = xstrdup(opt + 1); + *opt = '\0'; + } + } value = -1; for (i = 0; tunmode_desc[i].val != -1; i++) if (strcmp(tunmode_desc[i].text, arg) == 0) { @@ -2308,14 +2316,6 @@ process_server_config_line_depth(ServerOptions *options, char *line, *intptr = value; break; - case sTunnelOptions: - charptr = &options->tunnel_options; - arg = argv_next(&ac, &av); - if (*activep && *charptr == NULL) - *charptr = xstrdup((arg == NULL) ? "" : arg); - break; - - case sInclude: if (cmdline) { fatal("Include directive not supported as a " @@ -3436,7 +3436,6 @@ dump_config(ServerOptions *o) } } dump_cfg_string(sPermitTunnel, s); - dump_cfg_string(sTunnelOptions, o->tunnel_options); printf("ipqos %s ", iptos2str(o->ip_qos_interactive)); printf("%s\n", iptos2str(o->ip_qos_bulk)); diff --git a/servconf.h b/servconf.h index d6122124b513..aaf63a2efab0 100644 --- a/servconf.h +++ b/servconf.h @@ -214,7 +214,7 @@ typedef struct { int permit_tun; - char* tunnel_options; + char* tun_options; char **permitted_opens; /* May also be one of PERMITOPEN_* */ u_int num_permitted_opens; diff --git a/serverloop.c b/serverloop.c index 86932e2ad16f..04176610d355 100644 --- a/serverloop.c +++ b/serverloop.c @@ -516,7 +516,7 @@ server_request_tun(struct ssh *ssh) goto done; tun = auth_opts->force_tun_device; } - sock = tun_open(tun, mode, options.tunnel_options, &ifname); + sock = tun_open(tun, mode, options.tun_options, &ifname); if (sock < 0) goto done; debug("Tunnel forwarding using interface %s", ifname); From e0296cdb1eb751c022db96e73da0d687fff74ee0 Mon Sep 17 00:00:00 2001 From: Giuseppe Guerrini Date: Tue, 1 Oct 2024 00:46:09 +0200 Subject: [PATCH 5/5] Removed "TunnelOptions" option. Its function is now fulfilled by "PermitTunnel"(sshd) and "Tunnel" (ssh): you can append to the type of tunnel a ":" followed by options (e.g. Tunnel=ethernet:my_option) --- README-TAP-Windows.txt | 4 +++- openbsd-compat/port-net.c | 5 +++-- readconf.c | 13 ++++++++++--- servconf.c | 3 +-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/README-TAP-Windows.txt b/README-TAP-Windows.txt index dd69b2ebe171..eefb0b4928c3 100644 --- a/README-TAP-Windows.txt +++ b/README-TAP-Windows.txt @@ -21,7 +21,9 @@ begins with the prefix. The number of adapters created in this way is the number of simultaneous sessions that can be opened. For clients (ssh.exe) one single instance is usually enough, but for servers (sshd.exe) a largest number of reserved adapters is required. The name prefix SSH looks for can be -configured by setting the new option "TunnelOptions". At the moment, only +configured by appendig a ":" caracter and the prefix it to "ethernet" string +in "Tunnel" (or "PermitTunnel" sor sshd) option. +(e.g: "Tunnel=ethernet:MY_PREFIX")) . At the moment, only ASCII characters are allowed, although Windows uses WCHAR for adapter names (property "FriendlyName"). diff --git a/openbsd-compat/port-net.c b/openbsd-compat/port-net.c index 58b24749c9f4..d80120f54ce2 100644 --- a/openbsd-compat/port-net.c +++ b/openbsd-compat/port-net.c @@ -411,8 +411,9 @@ sys_tun_outfilter(struct ssh *ssh, struct Channel *c, // whose IfIndex match the given value. If the index is not // specified ("any"), the function takes the adapters whose // friendly name starts with "SSH Tunnel" (case insensitive) -// or whatever is configured (see "TunnelOptions" configuration -// item). +// or whatever is configured. The name prefix SSH looks for can be +// configured by appendig a ":" caracter and the prefix it to "ethernet" string +// in "Tunnel" (or "PermitTunnel" sor sshd) option. // - If a matching adapter if found, the function tries to open // and activate it. In case of failure, it takes the next matching // adapter. diff --git a/readconf.c b/readconf.c index c231e3bc2c6e..6738d9261f6f 100644 --- a/readconf.c +++ b/readconf.c @@ -1949,6 +1949,13 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, intptr = &options->tun_open; multistate_ptr = multistate_tunnel; arg = argv_next(&ac, &av); + if (arg != NULL) { + char* opt = strchr(arg, ':'); + if (opt != NULL) { + options->tun_options = xstrdup(opt + 1); + *opt = '\0'; + } + } goto parse_multistate_arg; case oTunnelDevice: @@ -2830,8 +2837,6 @@ fill_default_options(Options * options) options->hash_known_hosts = 0; if (options->tun_open == -1) options->tun_open = SSH_TUNMODE_NO; - if (options->tun_options == NULL) - options->tun_options = xstrdup(""); if (options->tun_local == -1) options->tun_local = SSH_TUNID_ANY; if (options->tun_remote == -1) @@ -3582,7 +3587,9 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); - dump_cfg_fmtint(oTunnel, o->tun_open); + printf("%s %s%s%s\n", lookup_opcode_name(oTunnel), fmt_intarg(oTunnel, o->tun_open), + ((o->tun_options == NULL) ? "" : ":"), + ((o->tun_options == NULL) ? "" : o->tun_options)); dump_cfg_fmtint(oVerifyHostKeyDNS, o->verify_host_key_dns); dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); diff --git a/servconf.c b/servconf.c index d98fa86e7b1d..e7329ed92609 100644 --- a/servconf.c +++ b/servconf.c @@ -472,8 +472,6 @@ fill_default_server_options(ServerOptions *options) } if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; - if (options->tun_options == NULL) - options->tun_options = xstrdup(""); if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_DSCP_AF21; if (options->ip_qos_bulk == -1) @@ -3026,6 +3024,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) free(dst->chroot_directory); dst->chroot_directory = NULL; } + M_CP_STROPT(tun_options); /* Subsystems require merging. */ servconf_merge_subsystems(dst, src);