From c67d59cd5c30534a4108945294284f29df7a6c84 Mon Sep 17 00:00:00 2001 From: james Date: Mon, 31 Oct 2005 03:01:17 +0000 Subject: Windows reliability changes: * Added code to make sure that the local PATH environmental variable points to the Windows system32 directory. * Added new --ip-win32 adaptive mode which tries 'dynamic' and then fails over to 'netsh' if the DHCP negotiation fails. * Made --ip-win32 adaptive the default. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@739 e7ae566f-a301-0410-adde-c780ea21d3b5 --- errlevel.h | 1 + forward.c | 10 +- init.c | 6 +- misc.c | 30 +++++ misc.h | 2 + options.c | 12 +- ping.c | 2 +- plugin.h | 1 - route.c | 2 + ssl.c | 2 - tun.c | 435 +++++++++++++++++++++++++++++++++++++++++++++++-------------- tun.h | 24 +++- 12 files changed, 412 insertions(+), 115 deletions(-) diff --git a/errlevel.h b/errlevel.h index d7db647..cbe8336 100644 --- a/errlevel.h +++ b/errlevel.h @@ -131,6 +131,7 @@ #define D_SHOW_PKCS11 LOGLEV(7, 70, M_DEBUG) /* show PKCS#11 actions */ #define D_ALIGN_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose struct alignment info */ #define D_PACKET_TRUNC_DEBUG LOGLEV(7, 70, M_DEBUG) /* PACKET_TRUNCATION_CHECK verbose */ +#define D_PING LOGLEV(7, 70, M_DEBUG) /* PING send/receive messages */ #define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */ #define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */ diff --git a/forward.c b/forward.c index ae2122f..338d862 100644 --- a/forward.c +++ b/forward.c @@ -274,8 +274,12 @@ check_add_routes_dowork (struct context *c) else { msg (D_ROUTE, "Route: Waiting for TUN/TAP interface to come up..."); + if (c->c1.tuntap) + tun_standby (c->c1.tuntap); + update_time (); if (c->c2.route_wakeup.n != 1) event_timeout_init (&c->c2.route_wakeup, 1, now); + event_timeout_reset (&c->c2.ping_rec_interval); } } @@ -773,7 +777,7 @@ process_incoming_link (struct context *c) #endif #ifdef PACKET_TRUNCATION_CHECK - /* if (c->c2.buf.len > 1) --c->c2.buf.len; JYFIXME */ + /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ ipv4_packet_size_verify (BPTR (&c->c2.buf), BLEN (&c->c2.buf), TUNNEL_TYPE (c->c1.tuntap), @@ -807,7 +811,7 @@ process_incoming_link (struct context *c) /* Did we just receive an openvpn ping packet? */ if (is_ping_msg (&c->c2.buf)) { - dmsg (D_PACKET_CONTENT, "RECEIVED PING PACKET"); + dmsg (D_PING, "RECEIVED PING PACKET"); c->c2.buf.len = 0; /* drop packet */ } @@ -911,7 +915,7 @@ process_incoming_tun (struct context *c) process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf); #ifdef PACKET_TRUNCATION_CHECK - /* if (c->c2.buf.len > 1) --c->c2.buf.len; JYFIXME */ + /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ ipv4_packet_size_verify (BPTR (&c->c2.buf), BLEN (&c->c2.buf), TUNNEL_TYPE (c->c1.tuntap), diff --git a/init.c b/init.c index fa57a33..5f1a9bb 100644 --- a/init.c +++ b/init.c @@ -122,7 +122,7 @@ context_init_1 (struct context *c) } #endif -#if 0 /* JYFIXME -- test get_user_pass with GET_USER_PASS_NEED_OK flag */ +#if 0 /* test get_user_pass with GET_USER_PASS_NEED_OK flag */ { /* * In the management interface, you can okay the request by entering "needok token-insertion-request ok" @@ -175,6 +175,8 @@ context_gc_free (struct context *c) bool init_static (void) { + configure_path (); + #if defined(USE_CRYPTO) && defined(DMALLOC) openssl_dmalloc_init (); #endif @@ -964,6 +966,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) { event_timeout_init (&c->c2.route_wakeup, c->options.route_delay, now); event_timeout_init (&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now); + if (c->c1.tuntap) + tun_standby_init (c->c1.tuntap); } else { diff --git a/misc.c b/misc.c index df40ace..278e8d7 100644 --- a/misc.c +++ b/misc.c @@ -1372,3 +1372,33 @@ openvpn_sleep (const int n) #endif sleep (n); } + +/* + * Configure PATH. On Windows, sometimes PATH is not set correctly + * by default. + */ +void +configure_path (void) +{ +#ifdef WIN32 + FILE *fp; + fp = fopen ("c:\\windows\\system32\\route.exe", "rb"); + if (fp) + { + const int bufsiz = 512; + struct gc_arena gc = gc_new (); + struct buffer oldpath = alloc_buf_gc (bufsiz, &gc); + struct buffer newpath = alloc_buf_gc (bufsiz, &gc); + DWORD status; + fclose (fp); + status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); + if (status > 0) + { + buf_printf (&newpath, "C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;%s", BSTR(&oldpath)); + SetEnvironmentVariable ("PATH", BSTR(&newpath)); + /*printf ("PATH: %s\n", BSTR(&newpath));*/ + } + gc_free (&gc); + } +#endif +} diff --git a/misc.h b/misc.h index aec12c6..7ec70a9 100644 --- a/misc.h +++ b/misc.h @@ -257,4 +257,6 @@ const char *safe_print (const char *str, struct gc_arena *gc); */ void openvpn_sleep (const int n); +void configure_path (void); + #endif diff --git a/options.c b/options.c index 05a2d0f..324d525 100644 --- a/options.c +++ b/options.c @@ -612,7 +612,7 @@ init_options (struct options *o) o->tuntap_options.txqueuelen = 100; #endif #ifdef WIN32 - o->tuntap_options.ip_win32_type = IPW32_SET_DHCP_MASQ; + o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE; o->tuntap_options.dhcp_lease_time = 31536000; /* one year */ o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */ o->route_method = ROUTE_METHOD_IPAPI; @@ -1469,9 +1469,10 @@ options_postprocess (struct options *options, bool first_time) && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask))) msg (M_USAGE, "On Windows, --ip-win32 doesn't make sense unless --ifconfig is also used"); - if (options->tuntap_options.dhcp_options && - options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ) - msg (M_USAGE, "--dhcp-options requires --ip-win32 dynamic"); + if (options->tuntap_options.dhcp_options + && options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ + && options->tuntap_options.ip_win32_type != IPW32_SET_ADAPTIVE) + msg (M_USAGE, "--dhcp-options requires --ip-win32 dynamic or adaptive"); if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined) { @@ -4280,6 +4281,9 @@ add_option (struct options *options, goto err; } + if (index == IPW32_SET_ADAPTIVE) + options->route_delay_window = IPW32_SET_ADAPTIVE_DELAY_WINDOW; + if (index == IPW32_SET_DHCP_MASQ) { if (p[2]) diff --git a/ping.c b/ping.c index d91af7a..bee3543 100644 --- a/ping.c +++ b/ping.c @@ -92,5 +92,5 @@ check_ping_send_dowork (struct context *c) * encrypt, sign, etc. */ encrypt_sign (c, true); - dmsg (D_PACKET_CONTENT, "SENT PING"); + dmsg (D_PING, "SENT PING"); } diff --git a/plugin.h b/plugin.h index 1d564a7..5c604f1 100644 --- a/plugin.h +++ b/plugin.h @@ -75,7 +75,6 @@ struct plugin { struct plugin_per_client { - /* bool initialized; JYFIXME */ void *per_client_context[MAX_PLUGINS]; }; diff --git a/route.c b/route.c index 5bde6a6..cb21489 100644 --- a/route.c +++ b/route.c @@ -22,6 +22,8 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* JYFIXME WIN32 todo: add adaptive route-method */ + /* * Support routines for adding/deleting network routes. */ diff --git a/ssl.c b/ssl.c index 9c49420..878a24e 100644 --- a/ssl.c +++ b/ssl.c @@ -315,9 +315,7 @@ ssl_set_auth_nocache (void) void ssl_purge_auth (void) { -#if 1 /* JYFIXME -- todo: bad private key should trigger a signal, then this code can be included */ purge_user_pass (&passbuf, true); -#endif purge_user_pass (&auth_user_pass, true); } diff --git a/tun.c b/tun.c index a518e4e..0420817 100644 --- a/tun.c +++ b/tun.c @@ -47,6 +47,22 @@ #include "memdbg.h" +#ifdef WIN32 + +#define NI_TEST_FIRST (1<<0) +#define NI_IP_NETMASK (1<<1) +#define NI_OPTIONS (1<<2) + +static void netsh_ifconfig (const struct tuntap_options *to, + const char *flex_name, + const in_addr_t ip, + const in_addr_t netmask, + unsigned int flags); + +static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); + +#endif + #ifdef TARGET_SOLARIS static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual); #endif @@ -125,7 +141,7 @@ guess_tuntap_dev (const char *dev, const int dt = dev_type_enum (dev, dev_type); if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP) { - return get_netsh_id (dev_node, gc); + return netsh_get_id (dev_node, gc); } #endif @@ -768,8 +784,6 @@ do_ifconfig (struct tuntap *tt, #elif defined (WIN32) { - const char *netmask; - /* * Make sure that both ifconfig addresses are part of the * same .252 subnet. @@ -778,36 +792,30 @@ do_ifconfig (struct tuntap *tt, { verify_255_255_255_252 (tt->local, tt->remote_netmask); tt->adapter_netmask = ~3; - netmask = print_in_addr_t (tt->adapter_netmask, 0, &gc); } else { - netmask = ifconfig_remote_netmask; tt->adapter_netmask = tt->remote_netmask; } - /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ - openvpn_snprintf (command_line, sizeof (command_line), - "netsh interface ip set address \"%s\" static %s %s", - actual, - ifconfig_local, - netmask); - switch (tt->options.ip_win32_type) { case IPW32_SET_MANUAL: msg (M_INFO, "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)", actual, ifconfig_local, - netmask); + print_in_addr_t (tt->adapter_netmask, 0, &gc)); break; case IPW32_SET_NETSH: if (!strcmp (actual, "NULL")) msg (M_FATAL, "Error: When using --ip-win32 netsh, if you have more than one TAP-Win32 adapter, you must also specify --dev-node"); - netcmd_semaphore_lock (); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "ERROR: netsh command failed"); - netcmd_semaphore_release (); + + netsh_ifconfig (&tt->options, + actual, + tt->local, + tt->adapter_netmask, + NI_IP_NETMASK|NI_OPTIONS); + break; } tt->did_ifconfig = true; @@ -2262,7 +2270,7 @@ get_unspecified_device_guid (const int device_number, if (act) buf_printf (&actual, "%s", act); else - buf_printf (&actual, "NULL"); + buf_printf (&actual, "%s", tap_reg->guid); } /* Save GUID for return value */ @@ -2305,7 +2313,7 @@ get_device_guid (const char *name, if (act) buf_printf (&actual, "%s", act); else - buf_printf (&actual, "NULL"); + buf_printf (&actual, "%s", name); return BSTR (&ret); } @@ -2323,39 +2331,6 @@ get_device_guid (const char *name, return NULL; } -/* - * Return a TAP name for netsh commands. - */ -const char * -get_netsh_id (const char *dev_node, struct gc_arena *gc) -{ - const struct tap_reg *tap_reg = get_tap_reg (gc); - const struct panel_reg *panel_reg = get_panel_reg (gc); - struct buffer actual = alloc_buf_gc (256, gc); - const char *guid; - - at_least_one_tap_win32 (tap_reg); - - if (dev_node) - { - guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); - } - else - { - guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); - - if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Win32 adapter */ - guid = NULL; - } - - if (!guid) - return "NULL"; /* not found */ - else if (strcmp (BPTR (&actual), "NULL")) - return BPTR (&actual); /* control panel name */ - else - return guid; /* no control panel name, return GUID instead */ -} - /* * Get adapter info list */ @@ -2394,23 +2369,26 @@ get_per_adapter_info (const DWORD index, struct gc_arena *gc) IP_PER_ADAPTER_INFO *pi = NULL; DWORD status; - if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW) - { - msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - else + if (index != ~0) { - pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc); - if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS) - return pi; - else + if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW) { - msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s", + msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s", (unsigned int)status, strerror_win32 (status, gc)); } + else + { + pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc); + if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS) + return pi; + else + { + msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32 (status, gc)); + } + } } return pi; } @@ -2547,6 +2525,20 @@ get_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const int n, in_addr_t *ip, i return ret; } +static bool +test_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const in_addr_t ip, const in_addr_t netmask) +{ + if (ai) + { + in_addr_t ip_adapter = 0; + in_addr_t netmask_adapter = 0; + const bool status = get_adapter_ip_netmask (ai, 0, &ip_adapter, &netmask_adapter); + return (status && ip_adapter == ip && netmask_adapter == netmask); + } + else + return false; +} + const IP_ADAPTER_INFO * get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list) { @@ -2675,16 +2667,28 @@ adapter_index_of_ip (const IP_ADAPTER_INFO *list, const in_addr_t ip, int *count * Given an adapter index, return true if the adapter * is DHCP disabled. */ -static bool -dhcp_disabled (DWORD index) + +#define DHCP_STATUS_UNDEF 0 +#define DHCP_STATUS_ENABLED 1 +#define DHCP_STATUS_DISABLED 2 + +static int +dhcp_status (DWORD index) { struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc); - bool ret = false; - - if (ai && !ai->DhcpEnabled) - ret = true; + int ret = DHCP_STATUS_UNDEF; + if (index != ~0) + { + const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc); + if (ai) + { + if (ai->DhcpEnabled) + ret = DHCP_STATUS_ENABLED; + else + ret = DHCP_STATUS_DISABLED; + } + } gc_free (&gc); return ret; } @@ -2733,28 +2737,75 @@ delete_temp_addresses (DWORD index) * Get interface index for use with IP Helper API functions. */ static DWORD -get_interface_index (const char *guid) +get_adapter_index_method_1 (const char *guid) { struct gc_arena gc = gc_new (); - ULONG index; + ULONG index = ~0; DWORD status; wchar_t wbuf[256]; snwprintf (wbuf, SIZE (wbuf), L"\\DEVICE\\TCPIP_%S", guid); wbuf [SIZE(wbuf) - 1] = 0; if ((status = GetAdapterIndex (wbuf, &index)) != NO_ERROR) + index = ~0; + gc_free (&gc); + return index; +} + +static DWORD +get_adapter_index_method_2 (const char *guid) +{ + struct gc_arena gc = gc_new (); + DWORD index = ~0; + + const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc); + + while (list) { - msg (M_INFO, "NOTE: could not get adapter index for %S, status=%u : %s", - wbuf, - (unsigned int)status, - strerror_win32 (status, &gc)); - gc_free (&gc); - return (DWORD)~0; - } - else - { - gc_free (&gc); - return index; + if (!strcmp (guid, list->AdapterName)) + { + index = list->Index; + break; + } + list = list->Next; } + + gc_free (&gc); + return index; +} + +static DWORD +get_adapter_index (const char *guid) +{ + DWORD index; + index = get_adapter_index_method_1 (guid); + if (index == ~0) + index = get_adapter_index_method_2 (guid); + if (index == ~0) + msg (M_INFO, "NOTE: could not get adapter index for %s", guid); + return index; +} + +static DWORD +get_adapter_index_flexible (const char *name) /* actual name or GUID */ +{ + struct gc_arena gc = gc_new (); + DWORD index; + index = get_adapter_index_method_1 (name); + if (index == ~0) + index = get_adapter_index_method_2 (name); + if (index == ~0) + { + const struct tap_reg *tap_reg = get_tap_reg (&gc); + const struct panel_reg *panel_reg = get_panel_reg (&gc); + const char *guid = name_to_guid (name, tap_reg, panel_reg); + index = get_adapter_index_method_1 (guid); + if (index == ~0) + index = get_adapter_index_method_2 (guid); + } + if (index == ~0) + msg (M_INFO, "NOTE: could not get adapter index for name/GUID '%s'", name); + gc_free (&gc); + return index; } /* @@ -2869,7 +2920,7 @@ tap_allow_nonadmin_access (const char *dev_node) const struct panel_reg *panel_reg = get_panel_reg (&gc); const char *device_guid = NULL; HANDLE hand; - char guid_buffer[256]; + char actual_buffer[256]; char device_path[256]; at_least_one_tap_win32 (tap_reg); @@ -2877,7 +2928,7 @@ tap_allow_nonadmin_access (const char *dev_node) if (dev_node) { /* Get the device GUID for the device specified with --dev-node. */ - device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc); + device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc); if (!device_guid) msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node); @@ -2912,8 +2963,8 @@ tap_allow_nonadmin_access (const char *dev_node) while (true) { device_guid = get_unspecified_device_guid (device_number, - guid_buffer, - sizeof (guid_buffer), + actual_buffer, + sizeof (actual_buffer), tap_reg, panel_reg, &gc); @@ -3007,6 +3058,149 @@ dhcp_renew (const struct tuntap *tt) return ret; } +/* + * netsh functions + */ + +static void +netsh_command (const char *cmd, int n) +{ + int i; + for (i = 0; i < n; ++i) + { + bool status; + netcmd_semaphore_lock (); + msg (M_INFO, "NETSH: %s", cmd); + status = system_check (cmd, NULL, 0, "ERROR: netsh command failed"); + netcmd_semaphore_release (); + if (status) + return; + openvpn_sleep (5); + } + msg (M_FATAL, "NETSH: command failed"); +} + +static void +netsh_ifconfig (const struct tuntap_options *to, + const char *flex_name, + const in_addr_t ip, + const in_addr_t netmask, + unsigned int flags) +{ + struct gc_arena gc = gc_new (); + struct buffer out = alloc_buf_gc (256, &gc); + const IP_ADAPTER_INFO *ai = NULL; + const IP_PER_ADAPTER_INFO *pai = NULL; + + if (flags & NI_TEST_FIRST) + { + const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc); + const int index = get_adapter_index_flexible (flex_name); + ai = get_adapter (list, index); + pai = get_per_adapter_info (index, &gc); + } + + if (flags & NI_IP_NETMASK) + { + if (test_adapter_ip_netmask (ai, ip, netmask)) + { + msg (M_INFO, "NETSH: \"%s\" %s/%s [already set]", + flex_name, + print_in_addr_t (ip, 0, &gc), + print_in_addr_t (netmask, 0, &gc)); + } + else + { + /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ + buf_init (&out, 0); + buf_printf (&out, + "netsh interface ip set address \"%s\" static %s %s", + flex_name, + print_in_addr_t (ip, 0, &gc), + print_in_addr_t (netmask, 0, &gc)); + + netsh_command (BSTR(&out), 4); + } + } + + gc_free (&gc); +} + +static void +netsh_enable_dhcp (const struct tuntap_options *to, + const char *actual_name) +{ + struct gc_arena gc = gc_new (); + struct buffer out = alloc_buf_gc (256, &gc); + + /* example: netsh interface ip set address my-tap dhcp */ + buf_printf (&out, + "netsh interface ip set address \"%s\" dhcp", + actual_name); + + netsh_command (BSTR(&out), 4); + + gc_free (&gc); +} + +/* + * Return a TAP name for netsh commands. + */ +static const char * +netsh_get_id (const char *dev_node, struct gc_arena *gc) +{ + const struct tap_reg *tap_reg = get_tap_reg (gc); + const struct panel_reg *panel_reg = get_panel_reg (gc); + struct buffer actual = alloc_buf_gc (256, gc); + const char *guid; + + at_least_one_tap_win32 (tap_reg); + + if (dev_node) + { + guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); + } + else + { + guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); + + if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Win32 adapter */ + guid = NULL; + } + + if (!guid) + return "NULL"; /* not found */ + else if (strcmp (BPTR (&actual), "NULL")) + return BPTR (&actual); /* control panel name */ + else + return guid; /* no control panel name, return GUID instead */ +} + +/* + * Called iteratively on TAP-Win32 wait-for-initialization polling loop + */ +void +tun_standby_init (struct tuntap *tt) +{ + tt->standby_iter = 0; +} + +void +tun_standby (struct tuntap *tt) +{ + ++tt->standby_iter; + if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE + && tt->standby_iter % IPW32_SET_ADAPTIVE_TRY_NETSH == 0) + { + msg (M_INFO, "NOTE: --ip-win32 dynamic failed, now trying --ip-win32 netsh (this may take some time)"); + netsh_ifconfig (&tt->options, + tt->actual_name, + tt->local, + tt->adapter_netmask, + NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); + } +} + /* * Convert DHCP options from the command line / config file * into a raw DHCP-format options string. @@ -3091,6 +3285,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 char device_path[256]; const char *device_guid = NULL; DWORD len; + bool dhcp_masq = false; + bool dhcp_masq_post = false; /*netcmd_semaphore_lock ();*/ @@ -3117,14 +3313,14 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 { const struct tap_reg *tap_reg = get_tap_reg (&gc); const struct panel_reg *panel_reg = get_panel_reg (&gc); - char guid_buffer[256]; + char actual_buffer[256]; at_least_one_tap_win32 (tap_reg); if (dev_node) { /* Get the device GUID for the device specified with --dev-node. */ - device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc); + device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc); if (!device_guid) msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node); @@ -3156,8 +3352,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 while (true) { device_guid = get_unspecified_device_guid (device_number, - guid_buffer, - sizeof (guid_buffer), + actual_buffer, + sizeof (actual_buffer), tap_reg, panel_reg, &gc); @@ -3192,10 +3388,11 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 /* translate high-level device name into a device instance GUID using the registry */ - tt->actual_name = string_alloc (guid_buffer, NULL); + tt->actual_name = string_alloc (actual_buffer, NULL); } msg (M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path); + tt->adapter_index = get_adapter_index (device_guid); /* get driver version info */ { @@ -3230,6 +3427,42 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 } } + /* + * Preliminaries for setting TAP-Win32 adapter TCP/IP + * properties via --ip-win32 dynamic or --ip-win32 adaptive. + */ + if (tt->did_ifconfig_setup) + { + if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) + { + /* + * If adapter is set to non-DHCP, set to DHCP mode. + */ + if (dhcp_status (tt->adapter_index) == DHCP_STATUS_DISABLED) + netsh_enable_dhcp (&tt->options, tt->actual_name); + dhcp_masq = true; + dhcp_masq_post = true; + } + else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) + { + /* + * If adapter is set to non-DHCP, use netsh right away. + */ + if (dhcp_status (tt->adapter_index) != DHCP_STATUS_ENABLED) + { + netsh_ifconfig (&tt->options, + tt->actual_name, + tt->local, + tt->adapter_netmask, + NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); + } + else + { + dhcp_masq = true; + } + } + } + /* set point-to-point mode if TUN device */ if (tt->type == DEV_TYPE_TUN) @@ -3273,7 +3506,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 /* should we tell the TAP-Win32 driver to masquerade as a DHCP server as a means of setting the adapter address? */ - if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) + if (dhcp_masq) { uint32_t ep[4]; @@ -3320,6 +3553,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 ASSERT (ep[3] > 0); +#if 1 /* TAP_IOCTL_CONFIG_DHCP_MASQ -- disable to simulate bad DHCP negotiation */ if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof (ep), ep, sizeof (ep), &len, NULL)) @@ -3332,6 +3566,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 print_in_addr_t (ep[2], IA_NET_ORDER, &gc), ep[3] ); +#endif /* user-supplied DHCP options capability */ if (tt->options.dhcp_options) @@ -3368,8 +3603,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 /* possibly use IP Helper API to set IP address on adapter */ { - DWORD index = get_interface_index (device_guid); - tt->adapter_index = index; + const DWORD index = tt->adapter_index; /* flush arp cache */ if (index != (DWORD)~0) @@ -3393,10 +3627,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 * make sure the TCP/IP properties for the adapter are * set correctly. */ - if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) + if (dhcp_masq_post) { /* check dhcp enable status */ - if (dhcp_disabled (index)) + if (dhcp_status (index) == DHCP_STATUS_DISABLED) msg (M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'"); /* force an explicit DHCP lease renewal on TAP adapter? */ @@ -3420,7 +3654,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 } /* check dhcp enable status */ - if (dhcp_disabled (index)) + if (dhcp_status (index) == DHCP_STATUS_DISABLED) msg (M_WARN, "NOTE: You have selected (explicitly or by default) '--ip-win32 ipapi', which has a better chance of working correctly if the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'"); /* delete previously added IP addresses which were not @@ -3556,7 +3790,8 @@ static const struct ipset_names ipset_names[] = { {"manual"}, {"netsh"}, {"ipapi"}, - {"dynamic"} + {"dynamic"}, + {"adaptive"} }; int diff --git a/tun.h b/tun.h index 41264e6..6f66961 100644 --- a/tun.h +++ b/tun.h @@ -40,6 +40,10 @@ #ifdef WIN32 +/* time constants for --ip-win32 adaptive */ +#define IPW32_SET_ADAPTIVE_DELAY_WINDOW 300 +#define IPW32_SET_ADAPTIVE_TRY_NETSH 20 + struct tuntap_options { /* --ip-win32 options */ bool ip_win32_defined; @@ -48,7 +52,8 @@ struct tuntap_options { # define IPW32_SET_NETSH 1 /* "--ip-win32 netsh" */ # define IPW32_SET_IPAPI 2 /* "--ip-win32 ipapi" */ # define IPW32_SET_DHCP_MASQ 3 /* "--ip-win32 dynamic" */ -# define IPW32_SET_N 4 +# define IPW32_SET_ADAPTIVE 4 /* "--ip-win32 adaptive" */ +# define IPW32_SET_N 5 int ip_win32_type; /* --ip-win32 dynamic options */ @@ -155,6 +160,8 @@ struct tuntap /* Windows adapter index for TAP-Win32 adapter, ~0 if undefined */ DWORD adapter_index; + + int standby_iter; #else int fd; /* file descriptor for TUN/TAP dev */ #endif @@ -318,12 +325,13 @@ void tun_show_debug (struct tuntap *tt); bool dhcp_release (const struct tuntap *tt); bool dhcp_renew (const struct tuntap *tt); +void tun_standby_init (struct tuntap *tt); +void tun_standby (struct tuntap *tt); + int tun_read_queue (struct tuntap *tt, int maxsize); int tun_write_queue (struct tuntap *tt, struct buffer *buf); int tun_finalize (HANDLE h, struct overlapped_io *io, struct buffer *buf); -const char *get_netsh_id (const char *dev_node, struct gc_arena *gc); - static inline bool tuntap_stop (int status) { @@ -379,6 +387,16 @@ tuntap_stop (int status) return false; } +static inline void +tun_standby_init (struct tuntap *tt) +{ +} + +static inline void +tun_standby (struct tuntap *tt) +{ +} + #endif /* -- cgit v1.2.3