diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-12-07 13:14:25 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2016-12-07 13:14:25 +0100 |
commit | 820804a01d365f6d4f9305b9e072f8393f443fcb (patch) | |
tree | fa122587cf4af5ccd339fa4c127c5374ea9fe3b3 /src/openvpn/tun.c | |
parent | 354d158b7ea85b6e60c0de67000b1673361904a0 (diff) | |
parent | d53dba59e78da865c4fe820386ff2f4f76925f3b (diff) |
Merge tag 'upstream/2.4_rc1'
Upstream version 2.4~rc1
Diffstat (limited to 'src/openvpn/tun.c')
-rw-r--r-- | src/openvpn/tun.c | 163 |
1 files changed, 143 insertions, 20 deletions
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 77ae72f..572e168 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -68,6 +68,9 @@ static void netsh_ifconfig (const struct tuntap_options *to, const in_addr_t ip, const in_addr_t netmask, const unsigned int flags); +static void netsh_set_dns6_servers (const struct in6_addr *addr_list, + const int addr_len, + const char *flex_name); static void netsh_command (const struct argv *a, int n, int msglevel); static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); @@ -132,6 +135,74 @@ out: return ret; } +static bool +do_dns6_service (bool add, const struct tuntap *tt) +{ + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new (); + HANDLE pipe = tt->options.msg_channel; + int addr_len = add ? tt->options.dns6_len : 0; + + if (addr_len == 0 && add) /* no addresses to add */ + return true; + + dns_cfg_message_t dns = { + .header = { + (add ? msg_add_dns_cfg : msg_del_dns_cfg), + sizeof (dns_cfg_message_t), + 0 }, + .iface = { .index = tt->adapter_index, .name = "" }, + .domains = "", + .family = AF_INET6, + .addr_len = addr_len + }; + + /* interface name is required */ + strncpy (dns.iface.name, tt->actual_name, sizeof (dns.iface.name)); + dns.iface.name[sizeof (dns.iface.name) - 1] = '\0'; + + if (addr_len > _countof(dns.addr)) + { + addr_len = _countof(dns.addr); + dns.addr_len = addr_len; + msg(M_WARN, "Number of IPv6 DNS addresses sent to service truncated to %d", + addr_len); + } + + for (int i = 0; i < addr_len; ++i) + { + dns.addr[i].ipv6 = tt->options.dns6[i]; + } + + msg (D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service", + (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index); + + if (!WriteFile (pipe, &dns, sizeof (dns), &len, NULL) || + !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + { + msg (M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg (M_WARN, "TUN: %s IPv6 dns failed using service: %s [status=%u if_name=%s]", + (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), + ack.error_number, dns.iface.name); + goto out; + } + + msg (M_INFO, "IPv6 dns servers %s using service", (add ? "set" : "deleted")); + ret = true; + +out: + gc_free (&gc); + return ret; +} + #endif #ifdef TARGET_SOLARIS @@ -1372,9 +1443,16 @@ do_ifconfig (struct tuntap *tt, if ( do_ipv6 ) { - if (tt->options.msg_channel) + if (tt->options.ip_win32_type == IPW32_SET_MANUAL) + { + msg (M_INFO, "******** NOTE: Please manually set the v6 IP of '%s' to %s (if it is not already set)", + actual, + ifconfig_ipv6_local); + } + else if (tt->options.msg_channel) { do_address_service (true, AF_INET6, tt); + do_dns6_service (true, tt); } else { @@ -1388,10 +1466,15 @@ do_ifconfig (struct tuntap *tt, iface, ifconfig_ipv6_local ); netsh_command (&argv, 4, M_FATAL); + /* set ipv6 dns servers if any are specified */ + netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, actual); } /* explicit route needed */ - add_route_connected_v6_net(tt, es); + if (tt->options.ip_win32_type != IPW32_SET_MANUAL) + { + add_route_connected_v6_net(tt, es); + } } #else msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); @@ -1623,14 +1706,20 @@ void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { #define ANDROID_TUNNAME "vpnservice-tun" - int i; struct user_pass up; struct gc_arena gc = gc_new (); bool opentun; int oldtunfd = tt->fd; - for (i = 0; i < tt->options.dns_len; ++i) { + /* Prefer IPv6 DNS servers, + * Android will use the DNS server in the order we specify*/ + for (int i = 0; i < tt->options.dns6_len; i++) { + management_android_control (management, "DNS6SERVER", + print_in6_addr (tt->options.dns6[i], 0, &gc)); + } + + for (int i = 0; i < tt->options.dns_len; i++) { management_android_control (management, "DNSSERVER", print_in_addr_t(tt->options.dns[i], 0, &gc)); } @@ -4508,23 +4597,9 @@ ipconfig_register_dns (const struct env_set *es) bool status; const char err[] = "ERROR: Windows ipconfig command failed"; - msg (D_TUNTAP_INFO, "Start net commands..."); + msg (D_TUNTAP_INFO, "Start ipconfig commands for register-dns..."); netcmd_semaphore_lock (); - argv_printf (&argv, "%s%sc stop dnscache", - get_win_sys_path(), - WIN_NET_PATH_SUFFIX); - argv_msg (D_TUNTAP_INFO, &argv); - status = openvpn_execve_check (&argv, es, 0, err); - argv_reset(&argv); - - argv_printf (&argv, "%s%sc start dnscache", - get_win_sys_path(), - WIN_NET_PATH_SUFFIX); - argv_msg (D_TUNTAP_INFO, &argv); - status = openvpn_execve_check (&argv, es, 0, err); - argv_reset(&argv); - argv_printf (&argv, "%s%sc /flushdns", get_win_sys_path(), WIN_IPCONFIG_PATH_SUFFIX); @@ -4540,7 +4615,7 @@ ipconfig_register_dns (const struct env_set *es) argv_reset(&argv); netcmd_semaphore_release (); - msg (D_TUNTAP_INFO, "End net commands..."); + msg (D_TUNTAP_INFO, "End ipconfig commands for register-dns..."); } void @@ -4617,6 +4692,41 @@ ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias) return false; } +/** + * Set the ipv6 dns servers on the specified interface. + * The list of dns servers currently set on the interface + * are cleared first. + * No action is taken if number of addresses (addr_len) < 1. + */ +static void +netsh_set_dns6_servers (const struct in6_addr *addr_list, + const int addr_len, + const char *flex_name) +{ + struct gc_arena gc = gc_new (); + struct argv argv = argv_new (); + + for (int i = 0; i < addr_len; ++i) + { + const char *fmt = (i == 0) ? + "%s%sc interface ipv6 set dns %s static %s" + : "%s%sc interface ipv6 add dns %s %s"; + argv_printf (&argv, fmt, get_win_sys_path(), + NETSH_PATH_SUFFIX, flex_name, + print_in6_addr (addr_list[i], 0, &gc)); + + /* disable slow address validation on Windows 7 and higher */ + if (win32_version_info() >= WIN_7) + argv_printf_cat (&argv, "%s", "validate=no"); + + /* Treat errors while adding as non-fatal as we do not check for duplicates */ + netsh_command (&argv, 1, (i==0)? M_FATAL : M_NONFATAL); + } + + argv_reset (&argv); + gc_free (&gc); +} + static void netsh_ifconfig_options (const char *type, const in_addr_t *addr_list, @@ -5540,6 +5650,8 @@ close_tun (struct tuntap *tt) if (tt->options.msg_channel) { do_address_service (false, AF_INET6, tt); + if (tt->options.dns6_len > 0) + do_dns6_service (false, tt); } else { @@ -5563,6 +5675,17 @@ close_tun (struct tuntap *tt) ifconfig_ipv6_local); netsh_command (&argv, 1, M_WARN); + + /* delete ipv6 dns servers if any were set */ + if (tt->options.dns6_len > 0) + { + argv_printf (&argv, + "%s%sc interface ipv6 delete dns %s all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->actual_name); + netsh_command (&argv, 1, M_WARN); + } argv_reset (&argv); } } |