From: Kirill Isakov Date: Fri, 25 Mar 2022 17:29:07 +0000 (+0600) Subject: Replace MinGW with Windows to avoid ambiguities X-Git-Url: https://www.tinc-vpn.org/git/?a=commitdiff_plain;h=373b0c12d9d0e8a3b449fd18be704e28dd6403e1;p=tinc Replace MinGW with Windows to avoid ambiguities --- diff --git a/.ci/tidy/run.sh b/.ci/tidy/run.sh index 36700a2e..bb975868 100755 --- a/.ci/tidy/run.sh +++ b/.ci/tidy/run.sh @@ -5,7 +5,7 @@ set -eu ./.ci/build.sh "$@" # Which paths to ignore. -paths='src/solaris src/mingw src/gcrypt' +paths='src/solaris src/windows src/gcrypt' case "$(uname -s)" in Linux) diff --git a/src/control.c b/src/control.c index 175f2bd0..86e0f68a 100644 --- a/src/control.c +++ b/src/control.c @@ -185,7 +185,7 @@ bool init_control(void) { free(localhost); fclose(f); -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS int unix_fd = socket(AF_UNIX, SOCK_STREAM, 0); if(unix_fd < 0) { @@ -232,7 +232,7 @@ bool init_control(void) { } void exit_control(void) { -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS unlink(unixsocketname); io_del(&unix_socket); close(unix_socket.fd); diff --git a/src/dropin.c b/src/dropin.c index 1489ee6c..d086ae18 100644 --- a/src/dropin.c +++ b/src/dropin.c @@ -130,7 +130,7 @@ int vasprintf(char **buf, const char *fmt, va_list ap) { #ifndef HAVE_GETTIMEOFDAY int gettimeofday(struct timeval *tv, void *tz) { -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS FILETIME ft; GetSystemTimeAsFileTime(&ft); uint64_t lt = (uint64_t)ft.dwLowDateTime | ((uint64_t)ft.dwHighDateTime << 32); diff --git a/src/dropin.h b/src/dropin.h index 9b196b6d..a1fb6c1b 100644 --- a/src/dropin.h +++ b/src/dropin.h @@ -52,7 +52,7 @@ extern int gettimeofday(struct timeval *, void *); } while (0) #endif -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #define mkdir(a, b) mkdir(a) #ifndef SHUT_RDWR #define SHUT_RDWR SD_BOTH diff --git a/src/event.c b/src/event.c index 5d0bcef0..2710a8b8 100644 --- a/src/event.c +++ b/src/event.c @@ -30,7 +30,7 @@ #include "net.h" struct timeval now; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS #ifdef HAVE_SYS_EPOLL_H static int epollset = 0; @@ -58,7 +58,7 @@ static inline int event_epoll_init(void) { #endif static int io_compare(const io_t *a, const io_t *b) { -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS return a->fd - b->fd; #else @@ -114,7 +114,7 @@ void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) { } io->fd = fd; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(io->fd != -1) { io->event = WSACreateEvent(); @@ -141,7 +141,7 @@ void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) { #endif } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event) { io->event = event; io_add(io, cb, data, -1, 0); @@ -167,7 +167,7 @@ void io_set(io_t *io, int flags) { return; } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS #ifdef HAVE_SYS_EPOLL_H epoll_ctl(epollset, EPOLL_CTL_DEL, io->fd, NULL); @@ -230,7 +230,7 @@ void io_del(io_t *io) { } io_set(io, 0); -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(io->fd != -1 && WSACloseEvent(io->event) == FALSE) { abort(); @@ -281,7 +281,7 @@ void timeout_del(timeout_t *timeout) { }; } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS // From Matz's Ruby #ifndef NSIG @@ -379,7 +379,7 @@ static struct timeval *timeout_execute(struct timeval *diff) { bool event_loop(void) { running = true; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS #ifdef HAVE_SYS_EPOLL_H diff --git a/src/event.h b/src/event.h index d0f19118..70d86f51 100644 --- a/src/event.h +++ b/src/event.h @@ -33,7 +33,7 @@ typedef void (*signal_cb_t)(void *data); typedef struct io_t { int fd; int flags; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS WSAEVENT event; #endif io_cb_t cb; @@ -57,7 +57,7 @@ typedef struct signal_t { extern struct timeval now; extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags); -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS extern void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event); #endif extern void io_del(io_t *io); diff --git a/src/fsck.c b/src/fsck.c index fdd584e7..e7262727 100644 --- a/src/fsck.c +++ b/src/fsck.c @@ -185,7 +185,7 @@ static void check_conffile(const char *nodename, bool server) { splay_empty_tree(&config); } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS typedef int uid_t; static uid_t getuid(void) { @@ -219,7 +219,7 @@ static void check_key_file_mode(const char *fname) { } } } -#endif // HAVE_MINGW +#endif // HAVE_WINDOWS static char *read_node_name(void) { if(access(tinc_conf, R_OK) == 0) { diff --git a/src/have.h b/src/have.h index f19c5992..36d17b60 100644 --- a/src/have.h +++ b/src/have.h @@ -21,7 +21,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #define WINVER 0x0600 #define _WIN32_WINNT 0x0600 #define WIN32_LEAN_AND_MEAN @@ -51,7 +51,7 @@ #define alloca(size) __builtin_alloca(size) #endif -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #ifdef HAVE_W32API_H #include #endif @@ -65,7 +65,7 @@ #include #include #endif -#endif // HAVE_MINGW +#endif // HAVE_WINDOWS #ifdef HAVE_TERMIOS_H #include @@ -237,7 +237,7 @@ #undef STATUS #endif -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #define SLASH "\\" #else #define SLASH "/" diff --git a/src/ifconfig.c b/src/ifconfig.c index 59aa94c3..f4ce313a 100644 --- a/src/ifconfig.c +++ b/src/ifconfig.c @@ -25,7 +25,7 @@ static long start; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS void ifconfig_header(FILE *out) { fprintf(out, "#!/bin/sh\n"); start = ftell(out); @@ -128,7 +128,7 @@ void ifconfig_address(FILE *out, const char *value) { return; } -#elif defined(HAVE_MINGW) +#elif defined(HAVE_WINDOWS) switch(address.type) { case SUBNET_MAC: @@ -226,7 +226,7 @@ void ifconfig_route(FILE *out, const char *value) { } } -#elif defined(HAVE_MINGW) +#elif defined(HAVE_WINDOWS) if(*gateway_str) { switch(subnet.type) { diff --git a/src/invitation.c b/src/invitation.c index d1e1e61d..22fd6146 100644 --- a/src/invitation.c +++ b/src/invitation.c @@ -996,7 +996,7 @@ ask_netname: char filename2[PATH_MAX]; snprintf(filename, sizeof(filename), "%s" SLASH "tinc-up.invitation", confbase); -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS snprintf(filename2, sizeof(filename2), "%s" SLASH "tinc-up.bat", confbase); #else snprintf(filename2, sizeof(filename2), "%s" SLASH "tinc-up", confbase); @@ -1028,7 +1028,7 @@ ask_netname: if(response == 'e') { char *command; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS const char *editor = getenv("VISUAL"); if(!editor) { @@ -1358,7 +1358,7 @@ next: continue; } -#if HAVE_MINGW +#if HAVE_WINDOWS // If socket has been shut down, recv() on Windows returns -1 and sets sockerrno // to WSAESHUTDOWN, while on UNIX-like operating systems recv() returns 0, so we diff --git a/src/keys.c b/src/keys.c index 5f93a5a9..0485c761 100644 --- a/src/keys.c +++ b/src/keys.c @@ -79,7 +79,7 @@ bool disable_old_keys(const char *filename, const char *what) { return false; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS // We cannot atomically replace files on Windows. char bakfile[PATH_MAX] = ""; snprintf(bakfile, sizeof(bakfile), "%s.bak", filename); @@ -95,7 +95,7 @@ bool disable_old_keys(const char *filename, const char *what) { return false; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS unlink(bakfile); #endif fprintf(stderr, "Warning: old key(s) found and disabled.\n"); @@ -128,7 +128,7 @@ ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile) { return NULL; } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS struct stat s; if(fstat(fileno(fp), &s)) { @@ -262,7 +262,7 @@ rsa_t *read_rsa_private_key(splay_tree_t *config_tree, char **keyfile) { return NULL; } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS struct stat s; if(fstat(fileno(fp), &s)) { diff --git a/src/logger.c b/src/logger.c index caaf038d..390023bb 100644 --- a/src/logger.c +++ b/src/logger.c @@ -34,7 +34,7 @@ debug_t debug_level = DEBUG_NOTHING; static logmode_t logmode = LOGMODE_STDERR; static pid_t logpid; static FILE *logfile = NULL; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static HANDLE loghandle = NULL; #endif static const char *logident = NULL; @@ -72,7 +72,7 @@ static void real_logger(debug_t level, int priority, const char *message) { break; case LOGMODE_SYSLOG: -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS { const char *messages[] = {message}; ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL); @@ -195,7 +195,7 @@ void openlogger(const char *ident, logmode_t mode) { break; case LOGMODE_SYSLOG: -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS loghandle = RegisterEventSource(NULL, logident); if(!loghandle) { @@ -248,7 +248,7 @@ void closelogger(void) { break; case LOGMODE_SYSLOG: -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS DeregisterEventSource(loghandle); break; #else diff --git a/src/logger.h b/src/logger.h index 5302582b..e8e9a576 100644 --- a/src/logger.h +++ b/src/logger.h @@ -44,7 +44,7 @@ typedef enum logmode_t { LOGMODE_SYSLOG } logmode_t; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #define LOG_EMERG EVENTLOG_ERROR_TYPE #define LOG_ALERT EVENTLOG_ERROR_TYPE #define LOG_CRIT EVENTLOG_ERROR_TYPE diff --git a/src/meson.build b/src/meson.build index 92f42fa5..e37c2db0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -159,7 +159,7 @@ elif os_name.endswith('bsd') or os_name in ['dragonfly', 'darwin'] elif os_name == 'sunos' subdir('solaris') elif os_name == 'windows' - subdir('mingw') + subdir('windows') endif foreach h : check_headers @@ -228,9 +228,7 @@ if not opt_miniupnpc.disabled() endif endif -if opt_curses.auto() and os_name == 'windows' - message('curses does not link under MinGW') -else +if not opt_curses.disabled() # The meta-dependency covers more alternatives, but is only available in 0.54+ curses_name = meson_version.version_compare('>=0.54') ? 'curses' : 'ncurses' dep_curses = dependency(curses_name, required: opt_curses, static: static) @@ -242,7 +240,7 @@ endif # Some distributions do not supply pkg-config files for readline if opt_readline.auto() and os_name == 'windows' - message('readline does not link under MinGW') + message('readline not available on Windows') else dep_readline = dependency('readline', required: opt_readline, static: static) if not dep_readline.found() diff --git a/src/mingw/common.h b/src/mingw/common.h deleted file mode 100644 index ff052c98..00000000 --- a/src/mingw/common.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef TINC_MINGW_COMMON_H -#define TINC_MINGW_COMMON_H - -/* - * TAP-Win32 -- A kernel driver to provide virtual tap device functionality - * on Windows. Originally derived from the CIPE-Win32 - * project by Damion K. Wilson, with extensive modifications by - * James Yonan. - * - * All source code which derives from the CIPE-Win32 project is - * Copyright (C) Damion K. Wilson, 2003, and is released under the - * GPL version 2 (see below). - * - * All other source code is Copyright (C) James Yonan, 2003-2004, - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -//=============================================== -// This file is included both by OpenVPN and -// the TAP-Win32 driver and contains definitions -// common to both. -//=============================================== - -//============= -// TAP IOCTLs -//============= - -#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) - -//================= -// Registry keys -//================= - -#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -//====================== -// Filesystem prefixes -//====================== - -#define USERMODEDEVICEDIR "\\\\.\\Global\\" -#define SYSDEVICEDIR "\\Device\\" -#define USERDEVICEDIR "\\DosDevices\\Global\\" -#define TAPSUFFIX ".tap" - -//========================================================= -// TAP_COMPONENT_ID -- This string defines the TAP driver -// type -- different component IDs can reside in the system -// simultaneously. -//========================================================= - -#define TAP_COMPONENT_ID "tap0801" - -#endif diff --git a/src/mingw/device.c b/src/mingw/device.c deleted file mode 100644 index 03a1d48c..00000000 --- a/src/mingw/device.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - device.c -- Interaction with Windows tap driver in a MinGW environment - Copyright (C) 2002-2005 Ivo Timmermans, - 2002-2022 Guus Sliepen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "../system.h" - -#include -#include - -#include "../conf.h" -#include "../device.h" -#include "../logger.h" -#include "../names.h" -#include "../net.h" -#include "../route.h" -#include "../utils.h" -#include "../xalloc.h" - -#include "common.h" - -int device_fd = -1; -static HANDLE device_handle = INVALID_HANDLE_VALUE; -static io_t device_read_io; -static OVERLAPPED device_read_overlapped; -static OVERLAPPED device_write_overlapped; -static vpn_packet_t device_read_packet; -static vpn_packet_t device_write_packet; -char *device = NULL; -char *iface = NULL; -static const char *device_info = "Windows tap device"; - -static void device_issue_read(void) { - int status; - - for(;;) { - ResetEvent(device_read_overlapped.hEvent); - - DWORD len; - status = ReadFile(device_handle, (void *)device_read_packet.data, MTU, &len, &device_read_overlapped); - - if(!status) { - if(GetLastError() != ERROR_IO_PENDING) - logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, - device, strerror(errno)); - - break; - } - - device_read_packet.len = len; - device_read_packet.priority = 0; - route(myself, &device_read_packet); - } -} - -static void device_handle_read(void *data, int flags) { - (void)data; - (void)flags; - - DWORD len; - - if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, FALSE)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Error getting read result from %s %s: %s", device_info, - device, strerror(errno)); - - if(GetLastError() != ERROR_IO_INCOMPLETE) { - /* Must reset event or it will keep firing. */ - ResetEvent(device_read_overlapped.hEvent); - } - - return; - } - - device_read_packet.len = len; - device_read_packet.priority = 0; - route(myself, &device_read_packet); - device_issue_read(); -} - -static bool setup_device(void) { - HKEY key, key2; - int i; - - char regpath[1024]; - char adapterid[1024]; - char adaptername[1024]; - char tapname[1024]; - DWORD len; - - bool found = false; - - int err; - - get_config_string(lookup_config(&config_tree, "Device"), &device); - get_config_string(lookup_config(&config_tree, "Interface"), &iface); - - if(device && iface) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); - } - - /* Open registry and look for network adapters */ - - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError())); - return false; - } - - for(i = 0; ; i++) { - len = sizeof(adapterid); - - if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) { - break; - } - - /* Find out more about this adapter */ - - snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); - - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) { - continue; - } - - len = sizeof(adaptername); - err = RegQueryValueEx(key2, "Name", 0, 0, (LPBYTE)adaptername, &len); - - RegCloseKey(key2); - - if(err) { - continue; - } - - if(device) { - if(!strcmp(device, adapterid)) { - found = true; - break; - } else { - continue; - } - } - - if(iface) { - if(!strcmp(iface, adaptername)) { - found = true; - break; - } else { - continue; - } - } - - snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); - device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); - - if(device_handle != INVALID_HANDLE_VALUE) { - found = true; - break; - } - } - - RegCloseKey(key); - - if(!found) { - logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!"); - return false; - } - - if(!device) { - device = xstrdup(adapterid); - } - - if(!iface) { - iface = xstrdup(adaptername); - } - - /* Try to open the corresponding tap device */ - - if(device_handle == INVALID_HANDLE_VALUE) { - snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device); - device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); - } - - if(device_handle == INVALID_HANDLE_VALUE) { - logger(DEBUG_ALWAYS, LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError())); - return false; - } - - /* Get version information from tap device */ - - { - ULONG info[3] = {0}; - DWORD len; - - if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), &len, NULL)) { - logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get version information from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); - } else { - logger(DEBUG_ALWAYS, LOG_INFO, "TAP-Windows driver version: %lu.%lu%s", info[0], info[1], info[2] ? " (DEBUG)" : ""); - - /* Warn if using >=9.21. This is because starting from 9.21, TAP-Win32 seems to use a different, less efficient write path. */ - if(info[0] == 9 && info[1] >= 21) - logger(DEBUG_ALWAYS, LOG_WARNING, - "You are using the newer (>= 9.0.0.21, NDIS6) series of TAP-Win32 drivers. " - "Using these drivers with tinc is not recommended as it can result in poor performance. " - "You might want to revert back to 9.0.0.9 instead."); - } - } - - /* Get MAC address from tap device */ - - if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) { - logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); - return false; - } - - if(routing_mode == RMODE_ROUTER) { - overwrite_mac = 1; - } - - device_info = "Windows tap device"; - - logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info); - - device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - return true; -} - -static void enable_device(void) { - logger(DEBUG_ALWAYS, LOG_INFO, "Enabling %s", device_info); - - ULONG status = 1; - DWORD len; - DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); - - /* We don't use the write event directly, but GetOverlappedResult() does, internally. */ - - io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent); - device_issue_read(); -} - -static void disable_device(void) { - logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info); - - io_del(&device_read_io); - - ULONG status = 0; - DWORD len; - DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); - - /* Note that we don't try to cancel ongoing I/O here - we just stop listening. - This is because some TAP-Win32 drivers don't seem to handle cancellation very well, - especially when combined with other events such as the computer going to sleep - cases - were observed where the GetOverlappedResult() would just block indefinitely and never - return in that case. */ -} - -static void close_device(void) { - CancelIo(device_handle); - - /* According to MSDN, CancelIo() does not necessarily wait for the operation to complete. - To prevent race conditions, make sure the operation is complete - before we close the event it's referencing. */ - - DWORD len; - - if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) { - logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError())); - } - - if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) { - logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError())); - } - - device_write_packet.len = 0; - - CloseHandle(device_read_overlapped.hEvent); - CloseHandle(device_write_overlapped.hEvent); - - CloseHandle(device_handle); - device_handle = INVALID_HANDLE_VALUE; - - free(device); - device = NULL; - free(iface); - iface = NULL; - device_info = NULL; -} - -static bool read_packet(vpn_packet_t *packet) { - (void)packet; - return false; -} - -static bool write_packet(vpn_packet_t *packet) { - DWORD outlen; - - logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", - packet->len, device_info); - - if(device_write_packet.len > 0) { - /* Make sure the previous write operation is finished before we start the next one; - otherwise we end up with multiple write ops referencing the same OVERLAPPED structure, - which according to MSDN is a no-no. */ - - if(!GetOverlappedResult(device_handle, &device_write_overlapped, &outlen, FALSE)) { - if(GetLastError() != ERROR_IO_INCOMPLETE) { - logger(DEBUG_ALWAYS, LOG_ERR, "Error completing previously queued write to %s %s: %s", device_info, device, winerror(GetLastError())); - } else { - logger(DEBUG_TRAFFIC, LOG_ERR, "Previous overlapped write to %s %s still in progress", device_info, device); - // drop this packet - return true; - } - } - } - - /* Copy the packet, since the write operation might still be ongoing after we return. */ - - memcpy(&device_write_packet, packet, sizeof(*packet)); - - ResetEvent(device_write_overlapped.hEvent); - - if(WriteFile(device_handle, DATA(&device_write_packet), device_write_packet.len, &outlen, &device_write_overlapped)) { - // Write was completed immediately. - device_write_packet.len = 0; - } else if(GetLastError() != ERROR_IO_PENDING) { - logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); - device_write_packet.len = 0; - return false; - } - - return true; -} - -const devops_t os_devops = { - .setup = setup_device, - .close = close_device, - .read = read_packet, - .write = write_packet, - .enable = enable_device, - .disable = disable_device, -}; diff --git a/src/mingw/meson.build b/src/mingw/meson.build deleted file mode 100644 index 5cd2c7ba..00000000 --- a/src/mingw/meson.build +++ /dev/null @@ -1,20 +0,0 @@ -check_headers += 'w32api.h' - -win_common_libs = ['ws2_32', 'iphlpapi', 'threads'] - -if opt_harden and cc_name != 'msvc' - win_common_libs += 'ssp' -endif - -foreach libname : win_common_libs - dep = dependency(libname, required: false) - if not dep.found() - dep = cc.find_library(libname) - endif - deps_common += dep -endforeach - -src_tincd += files('device.c') - -cdata.set('HAVE_MINGW', 1) - diff --git a/src/names.c b/src/names.c index c9318faf..fa3574b0 100644 --- a/src/names.c +++ b/src/names.c @@ -39,7 +39,7 @@ char *program_name = NULL; Set all files and paths according to netname */ void make_names(bool daemon) { -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS HKEY key; char installdir[1024] = ""; DWORD len = sizeof(installdir); @@ -58,7 +58,7 @@ void make_names(bool daemon) { identname = xstrdup("tinc"); } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) { if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) { @@ -94,7 +94,7 @@ void make_names(bool daemon) { } } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS (void)daemon; if(!logfilename) { diff --git a/src/net.c b/src/net.c index 7f844216..9669bc97 100644 --- a/src/net.c +++ b/src/net.c @@ -160,7 +160,7 @@ void terminate_connection(connection_t *c, bool report) { do_outgoing_connection(outgoing); } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS /* Clean up dead proxy processes */ while(waitpid(-1, NULL, WNOHANG) > 0); @@ -308,7 +308,7 @@ void handle_meta_connection_data(connection_t *c) { } } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS static void sigterm_handler(void *data) { logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum)); event_exit(); @@ -487,7 +487,7 @@ int main_loop(void) { 0, 0 }); -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS signal_t sighup = {0}; signal_t sigterm = {0}; signal_t sigquit = {0}; @@ -506,7 +506,7 @@ int main_loop(void) { return 1; } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS signal_del(&sighup); signal_del(&sigterm); signal_del(&sigquit); diff --git a/src/net.h b/src/net.h index 261d9c3c..1765b1cd 100644 --- a/src/net.h +++ b/src/net.h @@ -215,7 +215,7 @@ extern void load_all_nodes(void); extern void try_tx(struct node_t *n, bool mtu); extern void tarpit(int fd); -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS #define closesocket(s) close(s) #endif diff --git a/src/net_socket.c b/src/net_socket.c index a8e197b4..dfee573c 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -47,7 +47,7 @@ int fwmark; listen_socket_t listen_socket[MAXSOCKETS]; int listen_sockets; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS io_t unix_socket; #endif @@ -425,7 +425,7 @@ void finish_connecting(connection_t *c) { } static void do_outgoing_pipe(connection_t *c, const char *command) { -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS int fd[2]; if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) { @@ -783,7 +783,7 @@ void handle_new_meta_connection(void *data, int flags) { c->allow_request = ID; } -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS /* accept a new UNIX socket connection */ diff --git a/src/nolegacy/crypto.c b/src/nolegacy/crypto.c index d9df8288..6965218b 100644 --- a/src/nolegacy/crypto.c +++ b/src/nolegacy/crypto.c @@ -21,7 +21,7 @@ #include "../crypto.h" -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS static int random_fd = -1; diff --git a/src/openssl/crypto.c b/src/openssl/crypto.c index c2df0af3..fe5a5997 100644 --- a/src/openssl/crypto.c +++ b/src/openssl/crypto.c @@ -24,7 +24,7 @@ #include "../crypto.h" -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS static int random_fd = -1; diff --git a/src/process.c b/src/process.c index 7deaadfc..5e7b1db5 100644 --- a/src/process.c +++ b/src/process.c @@ -25,7 +25,7 @@ #include "process.h" #include "version.h" -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #include "utils.h" #endif @@ -42,7 +42,7 @@ bool use_logfile = false; /* Some functions the less gifted operating systems might lack... */ -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static SC_HANDLE manager = NULL; static SC_HANDLE service = NULL; static SERVICE_STATUS status = {0}; @@ -202,7 +202,7 @@ bool init_service(void) { bool detach(void) { logmode_t logmode; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); @@ -212,7 +212,7 @@ bool detach(void) { #endif if(do_detach) { -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS if(daemon(1, 0)) { logger(DEBUG_ALWAYS, LOG_ERR, "Couldn't detach from terminal: %s", strerror(errno)); diff --git a/src/process.h b/src/process.h index 1aae6dea..70f1c5ca 100644 --- a/src/process.h +++ b/src/process.h @@ -29,7 +29,7 @@ extern bool use_syslog; extern bool detach(void); -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #include "event.h" extern io_t stop_io; diff --git a/src/script.c b/src/script.c index b380931f..0b16c861 100644 --- a/src/script.c +++ b/src/script.c @@ -37,7 +37,7 @@ static void unputenv(const char *p) { ptrdiff_t len = e - p; #ifndef HAVE_UNSETENV -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS // Windows requires putenv("FOO=") to unset %FOO% len++; #endif @@ -148,7 +148,7 @@ bool execute_script(const char *name, environment_t *env) { /* First check if there is a script */ -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(!*scriptextension) { const char *pathext = getenv("PATHEXT"); diff --git a/src/sptps_test.c b/src/sptps_test.c index 1da0571c..baca66b3 100644 --- a/src/sptps_test.c +++ b/src/sptps_test.c @@ -25,7 +25,7 @@ #include -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS #include #endif @@ -37,7 +37,7 @@ #include "utils.h" #include "names.h" -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS #define closesocket(s) close(s) #endif @@ -160,7 +160,7 @@ static void usage(void) { fprintf(stderr, message, program_name); } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS int stdin_sock_fd = -1; @@ -308,7 +308,7 @@ server_err: return -1; } -#endif // HAVE_MINGW +#endif // HAVE_WINDOWS int main(int argc, char *argv[]) { program_name = argv[0]; @@ -428,7 +428,7 @@ int main(int argc, char *argv[]) { #endif -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static struct WSAData wsa_state; if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { @@ -566,7 +566,7 @@ int main(int argc, char *argv[]) { return 1; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(!readonly) { in = start_input_reader(); @@ -607,7 +607,7 @@ int main(int argc, char *argv[]) { } if(FD_ISSET(in, &fds)) { -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS ssize_t len = recv(in, buf, readsize, 0); #else ssize_t len = read(in, buf, readsize); @@ -621,7 +621,7 @@ int main(int argc, char *argv[]) { } if(len == 0) { -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS shutdown(in, SD_SEND); closesocket(in); #endif diff --git a/src/tincctl.c b/src/tincctl.c index 946e7498..c700f947 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -281,7 +281,7 @@ ask_filename: } } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(filename[0] != '\\' && filename[0] != '/' && !strchr(filename, ':')) { #else @@ -651,7 +651,7 @@ static bool stop_tincd(void) { return true; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static bool remove_service(void) { SC_HANDLE manager = NULL; SC_HANDLE service = NULL; @@ -748,7 +748,7 @@ bool connect_tincd(bool verbose) { fclose(f); -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS if((pid == 0) || (kill(pid, 0) && (errno == ESRCH))) { fprintf(stderr, "Could not find tincd running at pid %d\n", pid); @@ -886,7 +886,7 @@ static int cmd_start(int argc, char *argv[]) { char *c; char *slash = strrchr(program_name, '/'); -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if((c = strrchr(program_name, '\\')) > slash) { slash = c; @@ -904,7 +904,7 @@ static int cmd_start(int argc, char *argv[]) { char **nargv = xzalloc((optind + argc) * sizeof(*nargv)); char *arg0 = c; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS /* Windows has no real concept of an "argv array". A command line is just one string. The CRT of the new process will decode the command line string to generate argv before calling main(), and (by convention) @@ -925,7 +925,7 @@ static int cmd_start(int argc, char *argv[]) { nargv[nargc++] = argv[i]; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS int status = spawnvp(_P_WAIT, c, nargv); free(nargv); @@ -1024,7 +1024,7 @@ static int cmd_stop(int argc, char *argv[]) { return 1; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS return remove_service() ? EXIT_SUCCESS : EXIT_FAILURE; #else @@ -2058,7 +2058,7 @@ static int cmd_config(int argc, char *argv[]) { } // Replace the configuration file with the new one -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(remove(filename)) { fprintf(stderr, "Error replacing file %s: %s\n", filename, strerror(errno)); @@ -2234,7 +2234,7 @@ static int cmd_init(int argc, char *argv[]) { check_port(name); -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s" SLASH "tinc-up", confbase); @@ -2396,7 +2396,7 @@ static int cmd_edit(int argc, char *argv[]) { } char *command; -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS const char *editor = getenv("VISUAL"); if(!editor) { @@ -3290,7 +3290,7 @@ int main(int argc, char *argv[]) { return 0; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static struct WSAData wsa_state; if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { diff --git a/src/tincd.c b/src/tincd.c index 1ee8769f..9850eebb 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -37,7 +37,7 @@ #include #endif -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS #include #include #include @@ -66,7 +66,7 @@ static bool show_version = false; static bool do_mlock = false; #endif -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS /* If nonzero, chroot to netdir after startup. */ static bool do_chroot = false; @@ -96,7 +96,7 @@ static struct option const long_options[] = { {NULL, 0, NULL, 0} }; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static struct WSAData wsa_state; int main2(int argc, char **argv); #endif @@ -121,7 +121,7 @@ static void usage(bool status) { " --pidfile=FILENAME Write PID and control socket cookie to FILENAME.\n" " --bypass-security Disables meta protocol security, for debugging.\n" " -o, --option[HOST.]KEY=VALUE Set global/host configuration value.\n" -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS " -R, --chroot chroot to NET dir at startup.\n" " -U, --user=USER setuid to given USER at startup.\n" #endif @@ -196,7 +196,7 @@ static bool parse_options(int argc, char **argv) { list_insert_tail(&cmdline_conf, cfg); break; -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS case 'R': case 'U': @@ -289,7 +289,7 @@ exit_fail: } static bool drop_privs(void) { -#ifndef HAVE_MINGW +#ifndef HAVE_WINDOWS uid_t uid = 0; if(switchuser) { @@ -342,7 +342,7 @@ static bool drop_privs(void) { return true; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS # define setpriority(level) !SetPriorityClass(GetCurrentProcess(), (level)) static void stop_handler(void *data, int flags) { @@ -445,7 +445,7 @@ int main(int argc, char **argv) { return 1; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError())); @@ -511,7 +511,7 @@ int main(int argc, char **argv) { #endif -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS io_add_event(&stop_io, stop_handler, NULL, WSACreateEvent()); if(stop_io.event == FALSE) { diff --git a/src/utils.c b/src/utils.c index 8b0cd6ed..4150d92b 100644 --- a/src/utils.c +++ b/src/utils.c @@ -176,7 +176,7 @@ size_t b64encode_tinc_urlsafe(const void *src, char *dst, size_t length) { return b64encode_tinc_internal(src, dst, length, base64_urlsafe); } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS const char *winerror(int err) { static char buf[1024], *ptr; diff --git a/src/utils.h b/src/utils.h index 9756a3e0..5f1bd8b8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -34,7 +34,7 @@ extern size_t b64encode_tinc(const void *src, char *dst, size_t length); extern size_t b64encode_tinc_urlsafe(const void *src, char *dst, size_t length); extern size_t b64decode_tinc(const char *src, void *dst, size_t length); -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS extern const char *winerror(int); #define strerror(x) ((x)>0?strerror(x):winerror(GetLastError())) #define sockerrno WSAGetLastError() diff --git a/src/windows/common.h b/src/windows/common.h new file mode 100644 index 00000000..dd0e6dd8 --- /dev/null +++ b/src/windows/common.h @@ -0,0 +1,80 @@ +#ifndef TINC_WINDOWS_COMMON_H +#define TINC_WINDOWS_COMMON_H + +/* + * TAP-Win32 -- A kernel driver to provide virtual tap device functionality + * on Windows. Originally derived from the CIPE-Win32 + * project by Damion K. Wilson, with extensive modifications by + * James Yonan. + * + * All source code which derives from the CIPE-Win32 project is + * Copyright (C) Damion K. Wilson, 2003, and is released under the + * GPL version 2 (see below). + * + * All other source code is Copyright (C) James Yonan, 2003-2004, + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +//=============================================== +// This file is included both by OpenVPN and +// the TAP-Win32 driver and contains definitions +// common to both. +//=============================================== + +//============= +// TAP IOCTLs +//============= + +#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) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAPSUFFIX ".tap" + +//========================================================= +// TAP_COMPONENT_ID -- This string defines the TAP driver +// type -- different component IDs can reside in the system +// simultaneously. +//========================================================= + +#define TAP_COMPONENT_ID "tap0801" + +#endif diff --git a/src/windows/device.c b/src/windows/device.c new file mode 100644 index 00000000..51d09f72 --- /dev/null +++ b/src/windows/device.c @@ -0,0 +1,355 @@ +/* + device.c -- Interaction with the TAP-Windows driver + Copyright (C) 2002-2005 Ivo Timmermans, + 2002-2022 Guus Sliepen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "../system.h" + +#include +#include + +#include "../conf.h" +#include "../device.h" +#include "../logger.h" +#include "../names.h" +#include "../net.h" +#include "../route.h" +#include "../utils.h" +#include "../xalloc.h" + +#include "common.h" + +int device_fd = -1; +static HANDLE device_handle = INVALID_HANDLE_VALUE; +static io_t device_read_io; +static OVERLAPPED device_read_overlapped; +static OVERLAPPED device_write_overlapped; +static vpn_packet_t device_read_packet; +static vpn_packet_t device_write_packet; +char *device = NULL; +char *iface = NULL; +static const char *device_info = "Windows tap device"; + +static void device_issue_read(void) { + int status; + + for(;;) { + ResetEvent(device_read_overlapped.hEvent); + + DWORD len; + status = ReadFile(device_handle, (void *)device_read_packet.data, MTU, &len, &device_read_overlapped); + + if(!status) { + if(GetLastError() != ERROR_IO_PENDING) + logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, + device, strerror(errno)); + + break; + } + + device_read_packet.len = len; + device_read_packet.priority = 0; + route(myself, &device_read_packet); + } +} + +static void device_handle_read(void *data, int flags) { + (void)data; + (void)flags; + + DWORD len; + + if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, FALSE)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Error getting read result from %s %s: %s", device_info, + device, strerror(errno)); + + if(GetLastError() != ERROR_IO_INCOMPLETE) { + /* Must reset event or it will keep firing. */ + ResetEvent(device_read_overlapped.hEvent); + } + + return; + } + + device_read_packet.len = len; + device_read_packet.priority = 0; + route(myself, &device_read_packet); + device_issue_read(); +} + +static bool setup_device(void) { + HKEY key, key2; + int i; + + char regpath[1024]; + char adapterid[1024]; + char adaptername[1024]; + char tapname[1024]; + DWORD len; + + bool found = false; + + int err; + + get_config_string(lookup_config(&config_tree, "Device"), &device); + get_config_string(lookup_config(&config_tree, "Interface"), &iface); + + if(device && iface) { + logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); + } + + /* Open registry and look for network adapters */ + + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError())); + return false; + } + + for(i = 0; ; i++) { + len = sizeof(adapterid); + + if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) { + break; + } + + /* Find out more about this adapter */ + + snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); + + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) { + continue; + } + + len = sizeof(adaptername); + err = RegQueryValueEx(key2, "Name", 0, 0, (LPBYTE)adaptername, &len); + + RegCloseKey(key2); + + if(err) { + continue; + } + + if(device) { + if(!strcmp(device, adapterid)) { + found = true; + break; + } else { + continue; + } + } + + if(iface) { + if(!strcmp(iface, adaptername)) { + found = true; + break; + } else { + continue; + } + } + + snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); + device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + + if(device_handle != INVALID_HANDLE_VALUE) { + found = true; + break; + } + } + + RegCloseKey(key); + + if(!found) { + logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!"); + return false; + } + + if(!device) { + device = xstrdup(adapterid); + } + + if(!iface) { + iface = xstrdup(adaptername); + } + + /* Try to open the corresponding tap device */ + + if(device_handle == INVALID_HANDLE_VALUE) { + snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device); + device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + } + + if(device_handle == INVALID_HANDLE_VALUE) { + logger(DEBUG_ALWAYS, LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError())); + return false; + } + + /* Get version information from tap device */ + + { + ULONG info[3] = {0}; + DWORD len; + + if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), &len, NULL)) { + logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get version information from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); + } else { + logger(DEBUG_ALWAYS, LOG_INFO, "TAP-Windows driver version: %lu.%lu%s", info[0], info[1], info[2] ? " (DEBUG)" : ""); + + /* Warn if using >=9.21. This is because starting from 9.21, TAP-Win32 seems to use a different, less efficient write path. */ + if(info[0] == 9 && info[1] >= 21) + logger(DEBUG_ALWAYS, LOG_WARNING, + "You are using the newer (>= 9.0.0.21, NDIS6) series of TAP-Win32 drivers. " + "Using these drivers with tinc is not recommended as it can result in poor performance. " + "You might want to revert back to 9.0.0.9 instead."); + } + } + + /* Get MAC address from tap device */ + + if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); + return false; + } + + if(routing_mode == RMODE_ROUTER) { + overwrite_mac = 1; + } + + device_info = "Windows tap device"; + + logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info); + + device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + return true; +} + +static void enable_device(void) { + logger(DEBUG_ALWAYS, LOG_INFO, "Enabling %s", device_info); + + ULONG status = 1; + DWORD len; + DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); + + /* We don't use the write event directly, but GetOverlappedResult() does, internally. */ + + io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent); + device_issue_read(); +} + +static void disable_device(void) { + logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info); + + io_del(&device_read_io); + + ULONG status = 0; + DWORD len; + DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); + + /* Note that we don't try to cancel ongoing I/O here - we just stop listening. + This is because some TAP-Win32 drivers don't seem to handle cancellation very well, + especially when combined with other events such as the computer going to sleep - cases + were observed where the GetOverlappedResult() would just block indefinitely and never + return in that case. */ +} + +static void close_device(void) { + CancelIo(device_handle); + + /* According to MSDN, CancelIo() does not necessarily wait for the operation to complete. + To prevent race conditions, make sure the operation is complete + before we close the event it's referencing. */ + + DWORD len; + + if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError())); + } + + if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError())); + } + + device_write_packet.len = 0; + + CloseHandle(device_read_overlapped.hEvent); + CloseHandle(device_write_overlapped.hEvent); + + CloseHandle(device_handle); + device_handle = INVALID_HANDLE_VALUE; + + free(device); + device = NULL; + free(iface); + iface = NULL; + device_info = NULL; +} + +static bool read_packet(vpn_packet_t *packet) { + (void)packet; + return false; +} + +static bool write_packet(vpn_packet_t *packet) { + DWORD outlen; + + logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", + packet->len, device_info); + + if(device_write_packet.len > 0) { + /* Make sure the previous write operation is finished before we start the next one; + otherwise we end up with multiple write ops referencing the same OVERLAPPED structure, + which according to MSDN is a no-no. */ + + if(!GetOverlappedResult(device_handle, &device_write_overlapped, &outlen, FALSE)) { + if(GetLastError() != ERROR_IO_INCOMPLETE) { + logger(DEBUG_ALWAYS, LOG_ERR, "Error completing previously queued write to %s %s: %s", device_info, device, winerror(GetLastError())); + } else { + logger(DEBUG_TRAFFIC, LOG_ERR, "Previous overlapped write to %s %s still in progress", device_info, device); + // drop this packet + return true; + } + } + } + + /* Copy the packet, since the write operation might still be ongoing after we return. */ + + memcpy(&device_write_packet, packet, sizeof(*packet)); + + ResetEvent(device_write_overlapped.hEvent); + + if(WriteFile(device_handle, DATA(&device_write_packet), device_write_packet.len, &outlen, &device_write_overlapped)) { + // Write was completed immediately. + device_write_packet.len = 0; + } else if(GetLastError() != ERROR_IO_PENDING) { + logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); + device_write_packet.len = 0; + return false; + } + + return true; +} + +const devops_t os_devops = { + .setup = setup_device, + .close = close_device, + .read = read_packet, + .write = write_packet, + .enable = enable_device, + .disable = disable_device, +}; diff --git a/src/windows/meson.build b/src/windows/meson.build new file mode 100644 index 00000000..8766bc1b --- /dev/null +++ b/src/windows/meson.build @@ -0,0 +1,18 @@ +check_headers += 'w32api.h' + +win_common_libs = ['ws2_32', 'iphlpapi', 'threads'] + +if opt_harden and cc_name != 'msvc' + win_common_libs += 'ssp' +endif + +foreach libname : win_common_libs + dep = dependency(libname, required: false) + if not dep.found() + dep = cc.find_library(libname) + endif + deps_common += dep +endforeach + +src_tincd += files('device.c') + diff --git a/src/xalloc.h b/src/xalloc.h index 33f30d02..da74ce1f 100644 --- a/src/xalloc.h +++ b/src/xalloc.h @@ -67,7 +67,7 @@ static inline char *xstrdup(const char *s) { } static inline int xvasprintf(char **strp, const char *fmt, va_list ap) { -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS char buf[1024]; int result = vsnprintf(buf, sizeof(buf), fmt, ap); diff --git a/test/integration/splice.c b/test/integration/splice.c index 07c35030..e72d0c71 100644 --- a/test/integration/splice.c +++ b/test/integration/splice.c @@ -19,7 +19,7 @@ #include "../../src/system.h" -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static const char *winerror(int err) { static char buf[1024], *ptr; @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) { protocol = "17.7"; } -#ifdef HAVE_MINGW +#ifdef HAVE_WINDOWS static struct WSAData wsa_state; if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {