From a9c802b2a3f77f2b906e22f582681cdec0790c32 Mon Sep 17 00:00:00 2001 From: james Date: Thu, 22 Dec 2005 18:09:40 +0000 Subject: --ip-win32 adaptive is now the default. --ip-win32 netsh (or --ip-win32 adaptive when in netsh mode) can now set DNS/WINS addresses on the TAP-Win32 adapter. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@857 e7ae566f-a301-0410-adde-c780ea21d3b5 --- ChangeLog | 6 +- forward.c | 13 +++- init.c | 14 +++- openvpn.h | 11 ++++ options.c | 4 ++ tun.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- tun.h | 5 +- 7 files changed, 252 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9aa1378..e8c2005 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,7 +32,11 @@ $Id$ forcing a username/password re-query. * Fixed bug where if --daemon and --management-hold are used together, --user or --group options would be ignored. - +* --ip-win32 adaptive is now the default. +* --ip-win32 netsh (or --ip-win32 adaptive when in netsh + mode) can now set DNS/WINS addresses on the TAP-Win32 + adapter. + 2005.11.12 -- Version 2.1-beta7 * Allow blank passwords to be passed via the management diff --git a/forward.c b/forward.c index 5c35562..4705f44 100644 --- a/forward.c +++ b/forward.c @@ -275,7 +275,18 @@ check_add_routes_dowork (struct context *c) { msg (D_ROUTE, "Route: Waiting for TUN/TAP interface to come up..."); if (c->c1.tuntap) - tun_standby (c->c1.tuntap); + { + if (!tun_standby (c->c1.tuntap)) + { + c->sig->signal_received = SIGHUP; + c->sig->signal_text = "ip-fail"; + c->persist.restart_sleep_seconds = 10; +#ifdef WIN32 + show_routes (M_INFO|M_NOPREFIX); + show_adapters (M_INFO|M_NOPREFIX); +#endif + } + } update_time (); if (c->c2.route_wakeup.n != 1) event_timeout_init (&c->c2.route_wakeup, 1, now); diff --git a/init.c b/init.c index 8e730f1..930d220 100644 --- a/init.c +++ b/init.c @@ -75,8 +75,10 @@ void context_clear_all_except_first_time (struct context *c) { const bool first_time_save = c->first_time; + const struct context_persist cpsave = c->persist; context_clear (c); c->first_time = first_time_save; + c->persist = cpsave; } /* @@ -630,11 +632,15 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) /* Test if errors */ if (flags & ISC_ERRORS) + { #ifdef WIN32 - msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); + show_routes (M_INFO|M_NOPREFIX); + show_adapters (M_INFO|M_NOPREFIX); + msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); #else - msg (M_INFO, "%s With Errors", message); + msg (M_INFO, "%s With Errors", message); #endif + } else msg (M_INFO, "%s", message); @@ -1165,6 +1171,10 @@ socket_restart_pause (struct context *c) sec = 10; #endif + if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) + sec = c->persist.restart_sleep_seconds; + c->persist.restart_sleep_seconds = 0; + if (do_hold (NULL)) sec = 0; diff --git a/openvpn.h b/openvpn.h index 437a02f..3ddc1a7 100644 --- a/openvpn.h +++ b/openvpn.h @@ -117,6 +117,14 @@ struct context_buffers struct buffer read_tun_buf; }; +/* + * always-persistent context variables + */ +struct context_persist +{ + int restart_sleep_seconds; +}; + /* * level 0 context contains data related to * once-per OpenVPN instantiation events @@ -461,6 +469,9 @@ struct context /* set to true after we daemonize */ bool did_we_daemonize; + /* persistent across SIGHUP */ + struct context_persist persist; + /* level 0 context contains data related to once-per OpenVPN instantiation events such as daemonization */ diff --git a/options.c b/options.c index 1ef201c..75c8825 100644 --- a/options.c +++ b/options.c @@ -637,7 +637,11 @@ init_options (struct options *o) o->tuntap_options.txqueuelen = 100; #endif #ifdef WIN32 +#if 1 + o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE; +#else o->tuntap_options.ip_win32_type = IPW32_SET_DHCP_MASQ; +#endif 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; diff --git a/tun.c b/tun.c index eafa8d6..07f6ea4 100644 --- a/tun.c +++ b/tun.c @@ -50,6 +50,8 @@ #ifdef WIN32 +/* #define SIMULATE_DHCP_FAILED */ /* JYFIXME -- simulate bad DHCP negotiation */ + #define NI_TEST_FIRST (1<<0) #define NI_IP_NETMASK (1<<1) #define NI_OPTIONS (1<<2) @@ -3093,23 +3095,181 @@ netsh_command (const char *cmd, int n) for (i = 0; i < n; ++i) { bool status; + openvpn_sleep (1); 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); + openvpn_sleep (4); } msg (M_FATAL, "NETSH: command failed"); } +void +ip_addr_string_to_array (in_addr_t *dest, int *dest_len, const IP_ADDR_STRING *src) +{ + int i = 0; + while (src) + { + const unsigned int getaddr_flags = GETADDR_HOST_ORDER; + const char *ip_str = src->IpAddress.String; + in_addr_t ip = 0; + bool succeed = false; + + if (i >= *dest_len) + break; + if (!ip_str || !strlen (ip_str)) + break; + + ip = getaddr (getaddr_flags, ip_str, 0, &succeed, NULL); + if (!succeed) + break; + dest[i++] = ip; + + src = src->Next; + } + *dest_len = i; + +#if 0 + { + struct gc_arena gc = gc_new (); + msg (M_INFO, "ip_addr_string_to_array [%d]", *dest_len); + for (i = 0; i < *dest_len; ++i) + { + msg (M_INFO, "%s", print_in_addr_t (dest[i], 0, &gc)); + } + gc_free (&gc); + } +#endif +} + +static bool +ip_addr_one_to_one (const in_addr_t *a1, const int a1len, const IP_ADDR_STRING *ias) +{ + in_addr_t a2[8]; + int a2len = SIZE(a2); + int i; + + ip_addr_string_to_array (a2, &a2len, ias); + /*msg (M_INFO, "a1len=%d a2len=%d", a1len, a2len);*/ + if (a1len != a2len) + return false; + + for (i = 0; i < a1len; ++i) + { + if (a1[i] != a2[i]) + return false; + } + return true; +} + +static bool +ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias) +{ + in_addr_t aa[8]; + int len = SIZE(aa); + int i; + + ip_addr_string_to_array (aa, &len, ias); + for (i = 0; i < len; ++i) + { + if (addr == aa[i]) + return true; + } + return false; +} + +static void +netsh_ifconfig_options (const char *type, + const in_addr_t *addr_list, + const int addr_len, + const IP_ADDR_STRING *current, + const char *flex_name, + const bool test_first) +{ + struct gc_arena gc = gc_new (); + struct buffer out = alloc_buf_gc (256, &gc); + bool delete_first = false; + + /* first check if we should delete existing DNS/WINS settings from TAP interface */ + if (test_first) + { + if (!ip_addr_one_to_one (addr_list, addr_len, current)) + delete_first = true; + } + else + delete_first = true; + + /* delete existing DNS/WINS settings from TAP interface */ + if (delete_first) + { + buf_init (&out, 0); + buf_printf (&out, "netsh interface ip delete %s \"%s\" all", + type, + flex_name); + netsh_command (BSTR(&out), 2); + } + + /* add new DNS/WINS settings to TAP interface */ + { + int count = 0; + int i; + for (i = 0; i < addr_len; ++i) + { + if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current)) + { + const char *fmt = count ? + "netsh interface ip add %s \"%s\" %s" + : "netsh interface ip set %s \"%s\" static %s"; + + buf_init (&out, 0); + buf_printf (&out, fmt, + type, + flex_name, + print_in_addr_t (addr_list[i], 0, &gc)); + netsh_command (BSTR(&out), 2); + + ++count; + } + else + { + msg (M_INFO, "NETSH: \"%s\" %s %s [already set]", + flex_name, + type, + print_in_addr_t (addr_list[i], 0, &gc)); + } + } + } + + gc_free (&gc); +} + +static void +init_ip_addr_string2 (IP_ADDR_STRING *dest, const IP_ADDR_STRING *src1, const IP_ADDR_STRING *src2) +{ + CLEAR (dest[0]); + CLEAR (dest[1]); + if (src1) + { + dest[0] = *src1; + dest[0].Next = NULL; + } + if (src2) + { + dest[1] = *src2; + dest[0].Next = &dest[1]; + dest[1].Next = NULL; + } +} + 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) + const unsigned int flags) { struct gc_arena gc = gc_new (); struct buffer out = alloc_buf_gc (256, &gc); @@ -3147,6 +3307,30 @@ netsh_ifconfig (const struct tuntap_options *to, } } + /* set WINS/DNS options */ + if (flags & NI_OPTIONS) + { + IP_ADDR_STRING wins[2]; + CLEAR (wins[0]); + CLEAR (wins[1]); + + netsh_ifconfig_options ("dns", + to->dns, + to->dns_len, + pai ? &pai->DnsServerList : NULL, + flex_name, + BOOL_CAST (flags & NI_TEST_FIRST)); + if (ai && ai->HaveWins) + init_ip_addr_string2 (wins, &ai->PrimaryWinsServer, &ai->SecondaryWinsServer); + + netsh_ifconfig_options ("wins", + to->wins, + to->wins_len, + ai ? wins : NULL, + flex_name, + BOOL_CAST (flags & NI_TEST_FIRST)); + } + gc_free (&gc); } @@ -3209,20 +3393,28 @@ tun_standby_init (struct tuntap *tt) tt->standby_iter = 0; } -void +bool tun_standby (struct tuntap *tt) { + bool ret = true; ++tt->standby_iter; - if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE - && tt->standby_iter % IPW32_SET_ADAPTIVE_TRY_NETSH == 0) + if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) { - 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); + if (tt->standby_iter == IPW32_SET_ADAPTIVE_TRY_NETSH) + { + msg (M_INFO, "NOTE: now trying 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); + } + else if (tt->standby_iter >= IPW32_SET_ADAPTIVE_TRY_NETSH*2) + { + ret = false; + } } + return ret; } /* @@ -3577,7 +3769,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 */ +#ifndef SIMULATE_DHCP_FAILED /* this code is disabled to simulate bad DHCP negotiation */ if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof (ep), ep, sizeof (ep), &len, NULL)) @@ -3590,7 +3782,6 @@ 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) @@ -3604,6 +3795,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a TAP_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call"); free_buf (&buf); } +#endif } /* set driver media status to 'connected' */ diff --git a/tun.h b/tun.h index 6f66961..082a6fc 100644 --- a/tun.h +++ b/tun.h @@ -326,7 +326,7 @@ 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); +bool tun_standby (struct tuntap *tt); int tun_read_queue (struct tuntap *tt, int maxsize); int tun_write_queue (struct tuntap *tt, struct buffer *buf); @@ -392,9 +392,10 @@ tun_standby_init (struct tuntap *tt) { } -static inline void +static inline bool tun_standby (struct tuntap *tt) { + return true; } #endif -- cgit v1.2.3