summaryrefslogtreecommitdiff
path: root/src/openvpn/tun.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/tun.c')
-rw-r--r--src/openvpn/tun.c134
1 files changed, 106 insertions, 28 deletions
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 3639718..63f9d1b 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -5,7 +5,7 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -45,6 +45,7 @@
#include "manage.h"
#include "route.h"
#include "win32.h"
+#include "block_dns.h"
#include "memdbg.h"
@@ -124,7 +125,7 @@ do_address_service(const bool add, const short family, const struct tuntap *tt)
if (ack.error_number != NO_ERROR)
{
- msg(M_WARN, "TUN: %s address failed using service: %s [status=%u if_index=%lu]",
+ msg(M_WARN, "TUN: %s address failed using service: %s [status=%u if_index=%d]",
(add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc),
ack.error_number, addr.iface.index);
goto out;
@@ -838,12 +839,13 @@ delete_route_connected_v6_net(struct tuntap *tt,
r6.gateway = tt->local_ipv6;
r6.metric = 0; /* connected route */
r6.flags = RT_DEFINED | RT_ADDED | RT_METRIC_DEFINED;
+ route_ipv6_clear_host_bits(&r6);
delete_route_ipv6(&r6, tt, 0, es);
}
#endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */
#if defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \
- || defined(TARGET_OPENBSD)
+ || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD)
/* we can't use true subnet mode on tun on all platforms, as that
* conflicts with IPv6 (wants to use ND then, which we don't do),
* but the OSes want "a remote address that is different from ours"
@@ -888,7 +890,7 @@ do_ifconfig(struct tuntap *tt,
bool do_ipv6 = false;
struct argv argv = argv_new();
- msg( M_DEBUG, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d",
+ msg( D_LOW, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d",
tt->did_ifconfig_ipv6_setup );
/*
@@ -1089,7 +1091,7 @@ do_ifconfig(struct tuntap *tt,
actual
);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
argv_printf(&argv,
"%s %s %s %s netmask %s mtu %d up",
@@ -1171,7 +1173,7 @@ do_ifconfig(struct tuntap *tt,
}
}
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
/* Add a network route for the local tun interface */
struct route_ipv4 r;
@@ -1208,7 +1210,7 @@ do_ifconfig(struct tuntap *tt,
tun_mtu
);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
remote_end = create_arbitrary_remote( tt );
argv_printf(&argv,
@@ -1237,7 +1239,7 @@ do_ifconfig(struct tuntap *tt,
openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed");
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
struct route_ipv4 r;
CLEAR(r);
@@ -1267,6 +1269,8 @@ do_ifconfig(struct tuntap *tt,
#elif defined(TARGET_NETBSD)
+ in_addr_t remote_end; /* for "virtual" subnet topology */
+
if (tun)
{
argv_printf(&argv,
@@ -1278,14 +1282,15 @@ do_ifconfig(struct tuntap *tt,
tun_mtu
);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
+ remote_end = create_arbitrary_remote( tt );
argv_printf(&argv,
"%s %s %s %s mtu %d netmask %s up",
IFCONFIG_PATH,
actual,
ifconfig_local,
- ifconfig_local,
+ print_in_addr_t(remote_end, 0, &gc),
tun_mtu,
ifconfig_remote_netmask
);
@@ -1310,6 +1315,18 @@ do_ifconfig(struct tuntap *tt,
argv_msg(M_INFO, &argv);
openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed");
+ /* Add a network route for the local tun interface */
+ if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
+ {
+ struct route_ipv4 r;
+ CLEAR(r);
+ r.flags = RT_DEFINED;
+ r.network = tt->local & tt->remote_netmask;
+ r.netmask = tt->remote_netmask;
+ r.gateway = remote_end;
+ add_route(&r, tt, 0, NULL, es);
+ }
+
if (do_ipv6)
{
argv_printf(&argv,
@@ -1355,7 +1372,7 @@ do_ifconfig(struct tuntap *tt,
}
else
{
- if (tt->topology == TOP_SUBNET)
+ if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
argv_printf(&argv,
"%s %s %s %s netmask %s mtu %d up",
@@ -1385,7 +1402,7 @@ do_ifconfig(struct tuntap *tt,
tt->did_ifconfig = true;
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
struct route_ipv4 r;
CLEAR(r);
@@ -1428,7 +1445,7 @@ do_ifconfig(struct tuntap *tt,
tun_mtu
);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
remote_end = create_arbitrary_remote( tt );
argv_printf(&argv,
@@ -1458,7 +1475,7 @@ do_ifconfig(struct tuntap *tt,
tt->did_ifconfig = true;
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
{
struct route_ipv4 r;
CLEAR(r);
@@ -3683,7 +3700,8 @@ get_tap_reg(struct gc_arena *gc)
if (status == ERROR_SUCCESS && data_type == REG_SZ)
{
- if (!strcmp(component_id, TAP_WIN_COMPONENT_ID))
+ if (!strcmp(component_id, TAP_WIN_COMPONENT_ID) ||
+ !strcmp(component_id, "root\\" TAP_WIN_COMPONENT_ID))
{
struct tap_reg *reg;
ALLOC_OBJ_CLEAR_GC(reg, struct tap_reg, gc);
@@ -3790,7 +3808,7 @@ get_panel_reg(struct gc_arena *gc)
if (status != ERROR_SUCCESS || name_type != REG_SZ)
{
- dmsg(D_REGISTRY, "Error opening registry key: %s\\%s\\%s",
+ dmsg(D_REGISTRY, "Error opening registry key: %s\\%s\\%ls",
NETWORK_CONNECTIONS_KEY, connection_string, name_string);
}
else
@@ -4178,15 +4196,12 @@ get_adapter_info_list(struct gc_arena *gc)
else
{
pi = (PIP_ADAPTER_INFO) gc_malloc(size, false, gc);
- if ((status = GetAdaptersInfo(pi, &size)) == NO_ERROR)
- {
- return pi;
- }
- else
+ if ((status = GetAdaptersInfo(pi, &size)) != NO_ERROR)
{
msg(M_INFO, "GetAdaptersInfo #2 failed (status=%u) : %s",
(unsigned int)status,
strerror_win32(status, gc));
+ pi = NULL;
}
}
return pi;
@@ -4483,6 +4498,7 @@ adapter_index_of_ip(const IP_ADAPTER_INFO *list,
struct gc_arena gc = gc_new();
DWORD ret = TUN_ADAPTER_INDEX_INVALID;
in_addr_t highest_netmask = 0;
+ int lowest_metric = INT_MAX;
bool first = true;
if (count)
@@ -4496,9 +4512,14 @@ adapter_index_of_ip(const IP_ADAPTER_INFO *list,
if (is_ip_in_adapter_subnet(list, ip, &hn))
{
+ int metric = get_interface_metric(list->Index, AF_INET, NULL);
if (first || hn > highest_netmask)
{
highest_netmask = hn;
+ if (metric >= 0)
+ {
+ lowest_metric = metric;
+ }
if (count)
{
*count = 1;
@@ -4512,16 +4533,22 @@ adapter_index_of_ip(const IP_ADAPTER_INFO *list,
{
++*count;
}
+ if (metric >= 0 && metric < lowest_metric)
+ {
+ ret = list->Index;
+ lowest_metric = metric;
+ }
}
}
list = list->Next;
}
- dmsg(D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d",
+ dmsg(D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d metric=%d",
print_in_addr_t(ip, 0, &gc),
print_in_addr_t(highest_netmask, 0, &gc),
(int)ret,
- count ? *count : -1);
+ count ? *count : -1,
+ lowest_metric);
if (ret == TUN_ADAPTER_INDEX_INVALID && count)
{
@@ -4622,7 +4649,7 @@ get_adapter_index_method_1(const char *guid)
DWORD index;
ULONG aindex;
wchar_t wbuf[256];
- _snwprintf(wbuf, SIZE(wbuf), L"\\DEVICE\\TCPIP_%S", guid);
+ swprintf(wbuf, SIZE(wbuf), L"\\DEVICE\\TCPIP_%S", guid);
wbuf [SIZE(wbuf) - 1] = 0;
if (GetAdapterIndex(wbuf, &aindex) != NO_ERROR)
{
@@ -5345,6 +5372,49 @@ netsh_enable_dhcp(const struct tuntap_options *to,
argv_reset(&argv);
}
+/* Enable dhcp on tap adapter using iservice */
+static bool
+service_enable_dhcp(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;
+
+ enable_dhcp_message_t dhcp = {
+ .header = {
+ msg_enable_dhcp,
+ sizeof(enable_dhcp_message_t),
+ 0
+ },
+ .iface = { .index = tt->adapter_index, .name = "" }
+ };
+
+ if (!WriteFile(pipe, &dhcp, sizeof(dhcp), &len, NULL)
+ || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL))
+ {
+ msg(M_WARN, "Enable_dhcp: could not talk to service: %s [%lu]",
+ strerror_win32(GetLastError(), &gc), GetLastError());
+ goto out;
+ }
+
+ if (ack.error_number != NO_ERROR)
+ {
+ msg(M_NONFATAL, "TUN: enabling dhcp using service failed: %s [status=%u if_index=%d]",
+ strerror_win32(ack.error_number, &gc), ack.error_number, dhcp.iface.index);
+ }
+ else
+ {
+ msg(M_INFO, "DHCP enabled on interface %d using service", dhcp.iface.index);
+ ret = true;
+ }
+
+out:
+ gc_free(&gc);
+ return ret;
+}
+
/*
* Return a TAP name for netsh commands.
*/
@@ -5825,7 +5895,15 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
*/
if (dhcp_status(tt->adapter_index) == DHCP_STATUS_DISABLED)
{
- netsh_enable_dhcp(&tt->options, tt->actual_name);
+ /* try using the service if available, else directly execute netsh */
+ if (tt->options.msg_channel)
+ {
+ service_enable_dhcp(tt);
+ }
+ else
+ {
+ netsh_enable_dhcp(&tt->options, tt->actual_name);
+ }
}
dhcp_masq = true;
dhcp_masq_post = true;
@@ -6174,6 +6252,9 @@ close_tun(struct tuntap *tt)
{
if (tt->did_ifconfig_ipv6_setup)
{
+ /* remove route pointing to interface */
+ delete_route_connected_v6_net(tt, NULL);
+
if (tt->options.msg_channel)
{
do_address_service(false, AF_INET6, tt);
@@ -6187,9 +6268,6 @@ close_tun(struct tuntap *tt)
const char *ifconfig_ipv6_local;
struct argv argv = argv_new();
- /* remove route pointing to interface */
- delete_route_connected_v6_net(tt, NULL);
-
/* "store=active" is needed in Windows 8(.1) to delete the
* address we added (pointed out by Cedric Tabary).
*/