summaryrefslogtreecommitdiff
path: root/src/openvpn/tun.c
diff options
context:
space:
mode:
authorBernhard Schmidt <berni@debian.org>2020-08-15 21:29:54 +0200
committerBernhard Schmidt <berni@debian.org>2020-08-15 21:29:54 +0200
commit7c229d538824cb679351220ad8911f7b2daa7c23 (patch)
tree5c4d64b60da9018c7db3a9335a9787d326beade3 /src/openvpn/tun.c
parentd3986a312f5fbcfd0e78e6b147eef419fb4e5f54 (diff)
parent1079962e4c06f88a54e50d997c1b7e84303d30b4 (diff)
Update upstream source from tag 'upstream/2.5_beta1'
Update to upstream version '2.5~beta1' with Debian dir d53f9a482ac24eb491a294b26c24bb1d87afad24
Diffstat (limited to 'src/openvpn/tun.c')
-rw-r--r--src/openvpn/tun.c3282
1 files changed, 1857 insertions, 1425 deletions
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 80eaa2c..3045445 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -40,12 +40,13 @@
#include "tun.h"
#include "fdmisc.h"
#include "common.h"
-#include "misc.h"
+#include "run_command.h"
#include "socket.h"
#include "manage.h"
#include "route.h"
#include "win32.h"
#include "block_dns.h"
+#include "networking.h"
#include "memdbg.h"
@@ -57,6 +58,9 @@
#ifdef _WIN32
+const static GUID GUID_DEVCLASS_NET = { 0x4d36e972L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
+const static GUID GUID_DEVINTERFACE_NET = { 0xcac88484, 0x7515, 0x4c03, { 0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61 } };
+
/* #define SIMULATE_DHCP_FAILED */ /* simulate bad DHCP negotiation */
#define NI_TEST_FIRST (1<<0)
@@ -69,6 +73,10 @@ static void netsh_ifconfig(const struct tuntap_options *to,
const in_addr_t netmask,
const unsigned int flags);
+static void windows_set_mtu(const int iface_index,
+ const short family,
+ const int mtu);
+
static void netsh_set_dns6_servers(const struct in6_addr *addr_list,
const int addr_len,
const char *flex_name);
@@ -82,7 +90,6 @@ static DWORD get_adapter_index_flexible(const char *name);
static bool
do_address_service(const bool add, const short family, const struct tuntap *tt)
{
- DWORD len;
bool ret = false;
ack_message_t ack;
struct gc_arena gc = gc_new();
@@ -106,8 +113,8 @@ do_address_service(const bool add, const short family, const struct tuntap *tt)
if (addr.family == AF_INET)
{
- addr.address.ipv4.s_addr = tt->local;
- addr.prefix_len = 32;
+ addr.address.ipv4.s_addr = htonl(tt->local);
+ addr.prefix_len = netmask_to_netbits2(tt->adapter_netmask);
}
else
{
@@ -115,11 +122,8 @@ do_address_service(const bool add, const short family, const struct tuntap *tt)
addr.prefix_len = tt->netbits_ipv6;
}
- if (!WriteFile(pipe, &addr, sizeof(addr), &len, NULL)
- || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL))
+ if (!send_msg_iservice(pipe, &addr, sizeof(addr), &ack, "TUN"))
{
- msg(M_WARN, "TUN: could not talk to service: %s [%lu]",
- strerror_win32(GetLastError(), &gc), GetLastError());
goto out;
}
@@ -139,14 +143,15 @@ out:
}
static bool
-do_dns6_service(bool add, const struct tuntap *tt)
+do_dns_service(bool add, const short family, 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;
+ int len = family == AF_INET6 ? tt->options.dns6_len : tt->options.dns_len;
+ int addr_len = add ? len : 0;
+ const char *ip_proto_name = family == AF_INET6 ? "IPv6" : "IPv4";
if (addr_len == 0 && add) /* no addresses to add */
{
@@ -161,7 +166,7 @@ do_dns6_service(bool add, const struct tuntap *tt)
},
.iface = { .index = tt->adapter_index, .name = "" },
.domains = "",
- .family = AF_INET6,
+ .family = family,
.addr_len = addr_len
};
@@ -173,35 +178,39 @@ do_dns6_service(bool add, const struct tuntap *tt)
{
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);
+ msg(M_WARN, "Number of %s DNS addresses sent to service truncated to %d",
+ ip_proto_name, addr_len);
}
for (int i = 0; i < addr_len; ++i)
{
- dns.addr[i].ipv6 = tt->options.dns6[i];
+ if (family == AF_INET6)
+ {
+ dns.addr[i].ipv6 = tt->options.dns6[i];
+ }
+ else
+ {
+ dns.addr[i].ipv4.s_addr = htonl(tt->options.dns[i]);
+ }
}
- msg(D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service",
- (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index);
+ msg(D_LOW, "%s %s dns servers on '%s' (if_index = %d) using service",
+ (add ? "Setting" : "Deleting"), ip_proto_name, dns.iface.name, dns.iface.index);
- if (!WriteFile(pipe, &dns, sizeof(dns), &len, NULL)
- || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL))
+ if (!send_msg_iservice(pipe, &dns, sizeof(dns), &ack, "TUN"))
{
- 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),
+ msg(M_WARN, "TUN: %s %s dns failed using service: %s [status=%u if_name=%s]",
+ (add ? "adding" : "deleting"), ip_proto_name, 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"));
+ msg(M_INFO, "%s dns servers %s using service", ip_proto_name, (add ? "set" : "deleted"));
ret = true;
out:
@@ -209,6 +218,52 @@ out:
return ret;
}
+static bool
+do_set_mtu_service(const struct tuntap *tt, const short family, const int mtu)
+{
+ DWORD len;
+ bool ret = false;
+ ack_message_t ack;
+ struct gc_arena gc = gc_new();
+ HANDLE pipe = tt->options.msg_channel;
+ const char *family_name = (family == AF_INET6) ? "IPv6" : "IPv4";
+ set_mtu_message_t mtu_msg = {
+ .header = {
+ msg_set_mtu,
+ sizeof(set_mtu_message_t),
+ 0
+ },
+ .iface = {.index = tt->adapter_index},
+ .mtu = mtu,
+ .family = family
+ };
+ strncpynt(mtu_msg.iface.name, tt->actual_name, sizeof(mtu_msg.iface.name));
+ if (family == AF_INET6 && mtu < 1280)
+ {
+ msg(M_INFO, "NOTE: IPv6 interface MTU < 1280 conflicts with IETF standards and might not work");
+ }
+
+ if (!send_msg_iservice(pipe, &mtu_msg, sizeof(mtu_msg), &ack, "Set_mtu"))
+ {
+ goto out;
+ }
+
+ if (ack.error_number != NO_ERROR)
+ {
+ msg(M_NONFATAL, "TUN: setting %s mtu using service failed: %s [status=%u if_index=%d]",
+ family_name, strerror_win32(ack.error_number, &gc), ack.error_number, mtu_msg.iface.index);
+ }
+ else
+ {
+ msg(M_INFO, "%s MTU set to %d on interface %d using service", family_name, mtu, mtu_msg.iface.index);
+ ret = true;
+ }
+
+out:
+ gc_free(&gc);
+ return ret;
+}
+
#endif /* ifdef _WIN32 */
#ifdef TARGET_SOLARIS
@@ -342,16 +397,6 @@ ifconfig_sanity_check(bool tun, in_addr_t addr, int topology)
}
/*
- * For TAP-style devices, generate a broadcast address.
- */
-static in_addr_t
-generate_ifconfig_broadcast_addr(in_addr_t local,
- in_addr_t netmask)
-{
- return local | ~netmask;
-}
-
-/*
* Check that --local and --remote addresses do not
* clash with ifconfig addresses or subnet.
*/
@@ -460,13 +505,13 @@ check_subnet_conflict(const in_addr_t ip,
}
void
-warn_on_use_of_common_subnets(void)
+warn_on_use_of_common_subnets(openvpn_net_ctx_t *ctx)
{
struct gc_arena gc = gc_new();
struct route_gateway_info rgi;
const int needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED);
- get_default_gateway(&rgi);
+ get_default_gateway(&rgi, ctx);
if ((rgi.flags & needed) == needed)
{
const in_addr_t lan_network = rgi.gateway.addr & rgi.gateway.netmask;
@@ -561,8 +606,8 @@ is_tun_p2p(const struct tuntap *tt)
bool tun = false;
if (tt->type == DEV_TYPE_TAP
- || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
- || tt->type == DEV_TYPE_NULL )
+ || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
+ || tt->type == DEV_TYPE_NULL)
{
tun = false;
}
@@ -602,9 +647,7 @@ do_ifconfig_setenv(const struct tuntap *tt, struct env_set *es)
}
else
{
- const char *ifconfig_broadcast = print_in_addr_t(tt->broadcast, 0, &gc);
setenv_str(es, "ifconfig_netmask", ifconfig_remote_netmask);
- setenv_str(es, "ifconfig_broadcast", ifconfig_broadcast);
}
}
@@ -639,7 +682,8 @@ init_tun(const char *dev, /* --dev option */
struct addrinfo *local_public,
struct addrinfo *remote_public,
const bool strict_warn,
- struct env_set *es)
+ struct env_set *es,
+ openvpn_net_ctx_t *ctx)
{
struct gc_arena gc = gc_new();
struct tuntap *tt;
@@ -730,14 +774,6 @@ init_tun(const char *dev, /* --dev option */
}
}
- /*
- * If TAP-style interface, generate broadcast address.
- */
- if (!tun)
- {
- tt->broadcast = generate_ifconfig_broadcast_addr(tt->local, tt->remote_netmask);
- }
-
#ifdef _WIN32
/*
* Make sure that both ifconfig addresses are part of the
@@ -798,10 +834,40 @@ init_tun_post(struct tuntap *tt,
#ifdef _WIN32
overlapped_io_init(&tt->reads, frame, FALSE, true);
overlapped_io_init(&tt->writes, frame, TRUE, true);
- tt->rw_handle.read = tt->reads.overlapped.hEvent;
- tt->rw_handle.write = tt->writes.overlapped.hEvent;
tt->adapter_index = TUN_ADAPTER_INDEX_INVALID;
-#endif
+
+ if (tt->windows_driver == WINDOWS_DRIVER_WINTUN)
+ {
+ tt->wintun_send_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+ PAGE_READWRITE,
+ 0,
+ sizeof(struct tun_ring),
+ NULL);
+ tt->wintun_receive_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ sizeof(struct tun_ring),
+ NULL);
+ if ((tt->wintun_send_ring_handle == NULL) || (tt->wintun_receive_ring_handle == NULL))
+ {
+ msg(M_FATAL, "Cannot allocate memory for ring buffer");
+ }
+
+ tt->rw_handle.read = CreateEvent(NULL, FALSE, FALSE, NULL);
+ tt->rw_handle.write = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ((tt->rw_handle.read == NULL) || (tt->rw_handle.write == NULL))
+ {
+ msg(M_FATAL, "Cannot create events for ring buffer");
+ }
+ }
+ else
+ {
+ tt->rw_handle.read = tt->reads.overlapped.hEvent;
+ tt->rw_handle.write = tt->writes.overlapped.hEvent;
+ }
+#endif /* ifdef _WIN32 */
}
#if defined(_WIN32) \
@@ -812,7 +878,7 @@ init_tun_post(struct tuntap *tt,
* an extra call to "route add..."
* -> helper function to simplify code below
*/
-void
+static void
add_route_connected_v6_net(struct tuntap *tt,
const struct env_set *es)
{
@@ -824,12 +890,11 @@ add_route_connected_v6_net(struct tuntap *tt,
r6.gateway = tt->local_ipv6;
r6.metric = 0; /* connected route */
r6.flags = RT_DEFINED | RT_METRIC_DEFINED;
- add_route_ipv6(&r6, tt, 0, es);
+ add_route_ipv6(&r6, tt, 0, es, NULL);
}
void
-delete_route_connected_v6_net(struct tuntap *tt,
- const struct env_set *es)
+delete_route_connected_v6_net(const struct tuntap *tt)
{
struct route_ipv6 r6;
@@ -840,7 +905,7 @@ delete_route_connected_v6_net(struct tuntap *tt,
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);
+ delete_route_ipv6(&r6, tt, 0, NULL, NULL);
}
#endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */
@@ -871,739 +936,576 @@ create_arbitrary_remote( struct tuntap *tt )
}
#endif
-/* execute the ifconfig command through the shell */
-void
-do_ifconfig(struct tuntap *tt,
- const char *actual, /* actual device name */
- int tun_mtu,
- const struct env_set *es)
+/**
+ * do_ifconfig_ipv6 - perform platform specific ifconfig6 commands
+ *
+ * @param tt the tuntap interface context
+ * @param ifname the human readable interface name
+ * @param mtu the MTU value to set the interface to
+ * @param es the environment to be used when executing the commands
+ * @param ctx the networking API opaque context
+ */
+static void
+do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu,
+ const struct env_set *es, openvpn_net_ctx_t *ctx)
{
+#if !defined(TARGET_LINUX)
+ struct argv argv = argv_new();
struct gc_arena gc = gc_new();
+ const char *ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc);
+#endif
- if (tt->did_ifconfig_setup)
+#if defined(TARGET_LINUX)
+ if (net_iface_mtu_set(ctx, ifname, tun_mtu) < 0)
{
- bool tun = false;
- const char *ifconfig_local = NULL;
- const char *ifconfig_remote_netmask = NULL;
- const char *ifconfig_broadcast = NULL;
- const char *ifconfig_ipv6_local = NULL;
- bool do_ipv6 = false;
- struct argv argv = argv_new();
+ msg(M_FATAL, "Linux can't set mtu (%d) on %s", tun_mtu, ifname);
+ }
- msg( D_LOW, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d",
- tt->did_ifconfig_ipv6_setup );
+ if (net_iface_up(ctx, ifname, true) < 0)
+ {
+ msg(M_FATAL, "Linux can't bring %s up", ifname);
+ }
- /*
- * We only handle TUN/TAP devices here, not --dev null devices.
- */
- tun = is_tun_p2p(tt);
+ if (net_addr_v6_add(ctx, ifname, &tt->local_ipv6,
+ tt->netbits_ipv6) < 0)
+ {
+ msg(M_FATAL, "Linux can't add IPv6 to interface %s", ifname);
+ }
+#elif defined(TARGET_ANDROID)
+ char out6[64];
- /*
- * Set ifconfig parameters
- */
- ifconfig_local = print_in_addr_t(tt->local, 0, &gc);
- ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc);
+ openvpn_snprintf(out6, sizeof(out6), "%s/%d %d",
+ ifconfig_ipv6_local, tt->netbits_ipv6, tun_mtu);
+ management_android_control(management, "IFCONFIG6", out6);
+#elif defined(TARGET_SOLARIS)
+ argv_printf(&argv, "%s %s inet6 unplumb", IFCONFIG_PATH, ifname);
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, es, 0, NULL);
- if (tt->did_ifconfig_ipv6_setup)
- {
- ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc);
- do_ipv6 = true;
- }
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ const char *ifconfig_ipv6_remote = print_in6_addr(tt->remote_ipv6, 0, &gc);
- /*
- * If TAP-style device, generate broadcast address.
- */
- if (!tun)
- {
- ifconfig_broadcast = print_in_addr_t(tt->broadcast, 0, &gc);
- }
+ argv_printf(&argv, "%s %s inet6 plumb %s/%d %s mtu %d up",
+ IFCONFIG_PATH, ifname, ifconfig_ipv6_local,
+ tt->netbits_ipv6, ifconfig_ipv6_remote, tun_mtu);
+ }
+ else /* tap mode */
+ {
+ /* base IPv6 tap interface needs to be brought up first */
+ argv_printf(&argv, "%s %s inet6 plumb up", IFCONFIG_PATH, ifname);
+ argv_msg(M_INFO, &argv);
-#ifdef ENABLE_MANAGEMENT
- if (management)
+ if (!openvpn_execve_check(&argv, es, 0,
+ "Solaris ifconfig IPv6 (prepare) failed"))
{
- management_set_state(management,
- OPENVPN_STATE_ASSIGN_IP,
- NULL,
- &tt->local,
- &tt->local_ipv6,
- NULL,
- NULL);
+ solaris_error_close(tt, es, ifname, true);
}
-#endif
+ /* we might need to do "ifconfig %s inet6 auto-dhcp drop"
+ * after the system has noticed the interface and fired up
+ * the DHCPv6 client - but this takes quite a while, and the
+ * server will ignore the DHCPv6 packets anyway. So we don't.
+ */
-#if defined(TARGET_LINUX)
-#ifdef ENABLE_IPROUTE
- /*
- * Set the MTU for the device
+ /* static IPv6 addresses need to go to a subinterface (tap0:1)
+ * and we cannot set an mtu here (must go to the "parent")
*/
- argv_printf(&argv,
- "%s link set dev %s up mtu %d",
- iproute_path,
- actual,
- tun_mtu
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Linux ip link set failed");
+ argv_printf(&argv, "%s %s inet6 addif %s/%d up", IFCONFIG_PATH,
+ ifname, ifconfig_ipv6_local, tt->netbits_ipv6 );
+ }
+ argv_msg(M_INFO, &argv);
- if (tun)
- {
+ if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig IPv6 failed"))
+ {
+ solaris_error_close(tt, es, ifname, true);
+ }
- /*
- * Set the address for the device
- */
- argv_printf(&argv,
- "%s addr add dev %s local %s peer %s",
- iproute_path,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Linux ip addr add failed");
- }
- else
- {
- argv_printf(&argv,
- "%s addr add dev %s %s/%d broadcast %s",
- iproute_path,
- actual,
- ifconfig_local,
- netmask_to_netbits2(tt->remote_netmask),
- ifconfig_broadcast
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Linux ip addr add failed");
- }
- if (do_ipv6)
- {
- argv_printf( &argv,
- "%s -6 addr add %s/%d dev %s",
- iproute_path,
- ifconfig_ipv6_local,
- tt->netbits_ipv6,
- actual
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Linux ip -6 addr add failed");
- }
- tt->did_ifconfig = true;
-#else /* ifdef ENABLE_IPROUTE */
- if (tun)
- {
- argv_printf(&argv,
- "%s %s %s pointopoint %s mtu %d",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- else
- {
- argv_printf(&argv,
- "%s %s %s netmask %s mtu %d broadcast %s",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu,
- ifconfig_broadcast
- );
- }
+ if (tt->type != DEV_TYPE_TUN)
+ {
+ argv_printf(&argv, "%s %s inet6 mtu %d", IFCONFIG_PATH,
+ ifname, tun_mtu);
argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Linux ifconfig failed");
- if (do_ipv6)
- {
- argv_printf(&argv,
- "%s %s add %s/%d",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Linux ifconfig inet6 failed");
- }
- tt->did_ifconfig = true;
-
-#endif /*ENABLE_IPROUTE*/
-#elif defined(TARGET_ANDROID)
+ openvpn_execve_check(&argv, es, 0, "Solaris ifconfig IPv6 mtu failed");
+ }
+#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) \
+ || defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) \
+ || defined(TARGET_DRAGONFLY)
+ argv_printf(&argv, "%s %s inet6 %s/%d mtu %d up", IFCONFIG_PATH, ifname,
+ ifconfig_ipv6_local, tt->netbits_ipv6, tun_mtu);
+ argv_msg(M_INFO, &argv);
- if (do_ipv6)
- {
- struct buffer out6 = alloc_buf_gc(64, &gc);
- buf_printf(&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6);
- management_android_control(management, "IFCONFIG6",buf_bptr(&out6));
- }
+ openvpn_execve_check(&argv, es, S_FATAL,
+ "generic BSD ifconfig inet6 failed");
- struct buffer out = alloc_buf_gc(64, &gc);
+#if defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) \
+ || defined(TARGET_DARWIN)
+ /* and, hooray, we explicitly need to add a route... */
+ add_route_connected_v6_net(tt, es);
+#endif
+#elif defined(TARGET_AIX)
+ argv_printf(&argv, "%s %s inet6 %s/%d mtu %d up", IFCONFIG_PATH, ifname,
+ ifconfig_ipv6_local, tt->netbits_ipv6, tun_mtu);
+ argv_msg(M_INFO, &argv);
- char *top;
- switch (tt->topology)
- {
- case TOP_NET30:
- top = "net30";
- break;
+ /* AIX ifconfig will complain if it can't find ODM path in env */
+ es = env_set_create(NULL);
+ env_set_add(es, "ODMDIR=/etc/objrepos");
- case TOP_P2P:
- top = "p2p";
- break;
+ openvpn_execve_check(&argv, es, S_FATAL,
+ "generic BSD ifconfig inet6 failed");
- case TOP_SUBNET:
- top = "subnet";
- break;
+ env_set_destroy(es);
+#elif defined (_WIN32)
+ 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)",
+ ifname, ifconfig_ipv6_local);
+ }
+ else if (tt->options.msg_channel)
+ {
+ do_address_service(true, AF_INET6, tt);
+ add_route_connected_v6_net(tt, es);
+ do_dns_service(true, AF_INET6, tt);
+ do_set_mtu_service(tt, AF_INET6, tun_mtu);
+ }
+ else
+ {
+ /* example: netsh interface ipv6 set address interface=42
+ * 2001:608:8003::d store=active
+ */
+ char iface[64];
- default:
- top = "undef";
- }
+ openvpn_snprintf(iface, sizeof(iface), "interface=%lu",
+ tt->adapter_index);
+ argv_printf(&argv, "%s%s interface ipv6 set address %s %s store=active",
+ get_win_sys_path(), NETSH_PATH_SUFFIX, iface,
+ ifconfig_ipv6_local);
+ netsh_command(&argv, 4, M_FATAL);
+ add_route_connected_v6_net(tt, es);
+ /* set ipv6 dns servers if any are specified */
+ netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, ifname);
+ windows_set_mtu(tt->adapter_index, AF_INET6, tun_mtu);
+ }
+#else /* platforms we have no IPv6 code for */
+ msg(M_FATAL, "Sorry, but I don't know how to do IPv6 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script.");
+#endif /* outer "if defined(TARGET_xxx)" conditional */
- buf_printf(&out, "%s %s %d %s", ifconfig_local, ifconfig_remote_netmask, tun_mtu, top);
- management_android_control(management, "IFCONFIG", buf_bptr(&out));
+#if !defined(TARGET_LINUX)
+ gc_free(&gc);
+ argv_free(&argv);
+#endif
+}
-#elif defined(TARGET_SOLARIS)
- /* Solaris 2.6 (and 7?) cannot set all parameters in one go...
- * example:
- * ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up
- * ifconfig tun2 netmask 255.255.255.255
- */
- if (tun)
- {
- argv_printf(&argv,
- "%s %s %s %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
-
- argv_msg(M_INFO, &argv);
- if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-1 failed"))
- {
- solaris_error_close(tt, es, actual, false);
- }
+/**
+ * do_ifconfig_ipv4 - perform platform specific ifconfig commands
+ *
+ * @param tt the tuntap interface context
+ * @param ifname the human readable interface name
+ * @param mtu the MTU value to set the interface to
+ * @param es the environment to be used when executing the commands
+ * @param ctx the networking API opaque context
+ */
+static void
+do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
+ const struct env_set *es, openvpn_net_ctx_t *ctx)
+{
+ /*
+ * We only handle TUN/TAP devices here, not --dev null devices.
+ */
+ bool tun = is_tun_p2p(tt);
- argv_printf(&argv,
- "%s %s netmask 255.255.255.255",
- IFCONFIG_PATH,
- actual
- );
- }
- else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
- {
- argv_printf(&argv,
- "%s %s %s %s netmask %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- else
- {
- argv_printf(&argv,
- " %s %s %s netmask %s broadcast + up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask
- );
- }
+#if !defined(TARGET_LINUX)
+ const char *ifconfig_local = NULL;
+ const char *ifconfig_remote_netmask = NULL;
+ struct argv argv = argv_new();
+ struct gc_arena gc = gc_new();
- argv_msg(M_INFO, &argv);
- if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-2 failed"))
- {
- solaris_error_close(tt, es, actual, false);
- }
+ /*
+ * Set ifconfig parameters
+ */
+ ifconfig_local = print_in_addr_t(tt->local, 0, &gc);
+ ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc);
+#endif
- if (do_ipv6)
- {
- argv_printf(&argv, "%s %s inet6 unplumb",
- IFCONFIG_PATH, actual );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, 0, NULL);
+#if defined(TARGET_LINUX)
+ if (net_iface_mtu_set(ctx, ifname, tun_mtu) < 0)
+ {
+ msg(M_FATAL, "Linux can't set mtu (%d) on %s", tun_mtu, ifname);
+ }
- if (tt->type == DEV_TYPE_TUN)
- {
- const char *ifconfig_ipv6_remote =
- print_in6_addr(tt->remote_ipv6, 0, &gc);
-
- argv_printf(&argv,
- "%s %s inet6 plumb %s/%d %s up",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6,
- ifconfig_ipv6_remote
- );
- }
- else /* tap mode */
- {
- /* base IPv6 tap interface needs to be brought up first
- */
- argv_printf(&argv, "%s %s inet6 plumb up",
- IFCONFIG_PATH, actual );
- argv_msg(M_INFO, &argv);
- if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed"))
- {
- solaris_error_close(tt, es, actual, true);
- }
+ if (net_iface_up(ctx, ifname, true) < 0)
+ {
+ msg(M_FATAL, "Linux can't bring %s up", ifname);
+ }
- /* we might need to do "ifconfig %s inet6 auto-dhcp drop"
- * after the system has noticed the interface and fired up
- * the DHCPv6 client - but this takes quite a while, and the
- * server will ignore the DHCPv6 packets anyway. So we don't.
- */
-
- /* static IPv6 addresses need to go to a subinterface (tap0:1)
- */
- argv_printf(&argv,
- "%s %s inet6 addif %s/%d up",
- IFCONFIG_PATH, actual,
- ifconfig_ipv6_local, tt->netbits_ipv6 );
- }
- argv_msg(M_INFO, &argv);
- if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig IPv6 failed"))
- {
- solaris_error_close(tt, es, actual, true);
- }
+ if (tun)
+ {
+ if (net_addr_ptp_v4_add(ctx, ifname, &tt->local,
+ &tt->remote_netmask) < 0)
+ {
+ msg(M_FATAL, "Linux can't add IP to interface %s", ifname);
}
-
- if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
+ }
+ else
+ {
+ if (net_addr_v4_add(ctx, ifname, &tt->local,
+ netmask_to_netbits2(tt->remote_netmask)) < 0)
{
- /* Add a network route for the local tun interface */
- struct route_ipv4 r;
- CLEAR(r);
- r.flags = RT_DEFINED | RT_METRIC_DEFINED;
- r.network = tt->local & tt->remote_netmask;
- r.netmask = tt->remote_netmask;
- r.gateway = tt->local;
- r.metric = 0;
- add_route(&r, tt, 0, NULL, es);
+ msg(M_FATAL, "Linux can't add IP to interface %s", ifname);
}
+ }
+#elif defined(TARGET_ANDROID)
+ char out[64];
- tt->did_ifconfig = true;
+ char *top;
+ switch (tt->topology)
+ {
+ case TOP_NET30:
+ top = "net30";
+ break;
-#elif defined(TARGET_OPENBSD)
+ case TOP_P2P:
+ top = "p2p";
+ break;
- in_addr_t remote_end; /* for "virtual" subnet topology */
+ case TOP_SUBNET:
+ top = "subnet";
+ break;
- /*
- * On OpenBSD, tun interfaces are persistent if created with
- * "ifconfig tunX create", and auto-destroyed if created by
- * opening "/dev/tunX" (so we just use the /dev/tunX)
- */
+ default:
+ top = "undef";
+ }
- /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
- if (tun)
- {
- argv_printf(&argv,
- "%s %s %s %s mtu %d netmask 255.255.255.255 up -link0",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- 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 -link0",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- print_in_addr_t(remote_end, 0, &gc),
- tun_mtu,
- ifconfig_remote_netmask
- );
- }
- else
- {
- argv_printf(&argv,
- "%s %s %s netmask %s mtu %d broadcast %s link0",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu,
- ifconfig_broadcast
- );
- }
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed");
+ openvpn_snprintf(out, sizeof(out), "%s %s %d %s", ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu, top);
+ management_android_control(management, "IFCONFIG", out);
- /* Add a network route for the local tun interface */
- if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
+#elif defined(TARGET_SOLARIS)
+ /* Solaris 2.6 (and 7?) cannot set all parameters in one go...
+ * example:
+ * ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up
+ * ifconfig tun2 netmask 255.255.255.255
+ */
+ if (tun)
+ {
+ argv_printf(&argv, "%s %s %s %s mtu %d up", IFCONFIG_PATH, ifname,
+ ifconfig_local, ifconfig_remote_netmask, tun_mtu);
+
+ argv_msg(M_INFO, &argv);
+ if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-1 failed"))
{
- 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);
+ solaris_error_close(tt, es, ifname, false);
}
- if (do_ipv6)
- {
- argv_printf(&argv,
- "%s %s inet6 %s/%d",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed");
+ argv_printf(&argv, "%s %s netmask 255.255.255.255", IFCONFIG_PATH,
+ ifname);
+ }
+ else if (tt->topology == TOP_SUBNET)
+ {
+ argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
+ ifname, ifconfig_local, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ else
+ {
+ argv_printf(&argv, "%s %s %s netmask %s up",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask);
+ }
- /* and, hooray, we explicitely need to add a route... */
- add_route_connected_v6_net(tt, es);
- }
- tt->did_ifconfig = true;
+ argv_msg(M_INFO, &argv);
+ if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-2 failed"))
+ {
+ solaris_error_close(tt, es, ifname, false);
+ }
-#elif defined(TARGET_NETBSD)
+ if (!tun && tt->topology == TOP_SUBNET)
+ {
+ /* Add a network route for the local tun interface */
+ struct route_ipv4 r;
+ CLEAR(r);
+ r.flags = RT_DEFINED | RT_METRIC_DEFINED;
+ r.network = tt->local & tt->remote_netmask;
+ r.netmask = tt->remote_netmask;
+ r.gateway = tt->local;
+ r.metric = 0;
+ add_route(&r, tt, 0, NULL, es, NULL);
+ }
- in_addr_t remote_end; /* for "virtual" subnet topology */
+#elif defined(TARGET_OPENBSD)
- if (tun)
- {
- argv_printf(&argv,
- "%s %s %s %s mtu %d netmask 255.255.255.255 up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- 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,
- print_in_addr_t(remote_end, 0, &gc),
- tun_mtu,
- ifconfig_remote_netmask
- );
- }
- else
- {
- /*
- * NetBSD has distinct tun and tap devices
- * so we don't need the "link0" extra parameter to specify we want to do
- * tunneling at the ethernet level
- */
- argv_printf(&argv,
- "%s %s %s netmask %s mtu %d broadcast %s",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu,
- ifconfig_broadcast
- );
- }
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed");
+ in_addr_t remote_end; /* for "virtual" subnet topology */
- /* 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);
- }
+ /*
+ * On OpenBSD, tun interfaces are persistent if created with
+ * "ifconfig tunX create", and auto-destroyed if created by
+ * opening "/dev/tunX" (so we just use the /dev/tunX)
+ */
- if (do_ipv6)
- {
- argv_printf(&argv,
- "%s %s inet6 %s/%d",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed");
+ /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
+ if (tun)
+ {
+ argv_printf(&argv,
+ "%s %s %s %s mtu %d netmask 255.255.255.255 up -link0",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ else if (tt->topology == TOP_SUBNET)
+ {
+ remote_end = create_arbitrary_remote( tt );
+ argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up -link0",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ print_in_addr_t(remote_end, 0, &gc), tun_mtu,
+ ifconfig_remote_netmask);
+ }
+ else
+ {
+ argv_printf(&argv, "%s %s %s netmask %s mtu %d link0",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed");
- /* and, hooray, we explicitely need to add a route... */
- add_route_connected_v6_net(tt, es);
- }
- tt->did_ifconfig = true;
+ /* Add a network route for the local tun interface */
+ if (!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, NULL);
+ }
-#elif defined(TARGET_DARWIN)
+#elif defined(TARGET_NETBSD)
+ in_addr_t remote_end; /* for "virtual" subnet topology */
+
+ if (tun)
+ {
+ argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ else if (tt->topology == TOP_SUBNET)
+ {
+ remote_end = create_arbitrary_remote(tt);
+ argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH,
+ ifname, ifconfig_local, print_in_addr_t(remote_end, 0, &gc),
+ tun_mtu, ifconfig_remote_netmask);
+ }
+ else
+ {
/*
- * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD...
+ * NetBSD has distinct tun and tap devices
+ * so we don't need the "link0" extra parameter to specify we want to do
+ * tunneling at the ethernet level
*/
+ argv_printf(&argv, "%s %s %s netmask %s mtu %d",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed");
- argv_printf(&argv,
- "%s %s delete",
- IFCONFIG_PATH,
- actual);
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, 0, NULL);
- msg(M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure");
+ /* Add a network route for the local tun interface */
+ if (!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, NULL);
+ }
+
+#elif defined(TARGET_DARWIN)
+ /*
+ * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD...
+ */
+ argv_printf(&argv, "%s %s delete", IFCONFIG_PATH, ifname);
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, es, 0, NULL);
+ msg(M_INFO,
+ "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure");
- /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
- if (tun)
+
+ /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
+ if (tun)
+ {
+ argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ else
+ {
+ if (tt->topology == TOP_SUBNET)
{
- argv_printf(&argv,
- "%s %s %s %s mtu %d netmask 255.255.255.255 up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
+ argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up",
+ IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
}
else
{
- if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
- {
- argv_printf(&argv,
- "%s %s %s %s netmask %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- else
- {
- argv_printf(&argv,
- "%s %s %s netmask %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- }
-
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "Mac OS X ifconfig failed");
- tt->did_ifconfig = true;
-
- /* 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 = tt->local;
- add_route(&r, tt, 0, NULL, es);
+ argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
+ ifname, ifconfig_local, ifconfig_remote_netmask,
+ tun_mtu);
}
+ }
- if (do_ipv6)
- {
- argv_printf(&argv,
- "%s %s inet6 %s/%d",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed");
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, es, S_FATAL, "Mac OS X ifconfig failed");
- /* and, hooray, we explicitely need to add a route... */
- add_route_connected_v6_net(tt, es);
- }
+ /* Add a network route for the local tun interface */
+ if (!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 = tt->local;
+ add_route(&r, tt, 0, NULL, es, NULL);
+ }
#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
- in_addr_t remote_end; /* for "virtual" subnet topology */
+ in_addr_t remote_end; /* for "virtual" subnet topology */
- /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
- if (tun)
- {
- argv_printf(&argv,
- "%s %s %s %s mtu %d netmask 255.255.255.255 up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
- 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,
- print_in_addr_t(remote_end, 0, &gc),
- tun_mtu,
- ifconfig_remote_netmask
- );
- }
- else
- {
- argv_printf(&argv,
- "%s %s %s netmask %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
+ /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
+ if (tun)
+ {
+ argv_printf(&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up",
+ IFCONFIG_PATH, ifname, ifconfig_local,
+ ifconfig_remote_netmask, tun_mtu);
+ }
+ else if (tt->topology == TOP_SUBNET)
+ {
+ remote_end = create_arbitrary_remote( tt );
+ argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH,
+ ifname, ifconfig_local, print_in_addr_t(remote_end, 0, &gc),
+ tun_mtu, ifconfig_remote_netmask);
+ }
+ else
+ {
+ argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
+ ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu);
+ }
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD ifconfig failed");
- tt->did_ifconfig = true;
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD 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);
- }
+ /* Add a network route for the local tun interface */
+ if (!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, NULL);
+ }
- if (do_ipv6)
+#elif defined(TARGET_AIX)
+ {
+ /* AIX ifconfig will complain if it can't find ODM path in env */
+ struct env_set *aix_es = env_set_create(NULL);
+ env_set_add( aix_es, "ODMDIR=/etc/objrepos" );
+
+ if (tun)
{
- argv_printf(&argv,
- "%s %s inet6 %s/%d",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
+ msg(M_FATAL, "no tun support on AIX (canthappen)");
}
-#elif defined(TARGET_AIX)
- {
- /* AIX ifconfig will complain if it can't find ODM path in env */
- struct env_set *aix_es = env_set_create(NULL);
- env_set_add( aix_es, "ODMDIR=/etc/objrepos" );
+ /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */
+ argv_printf(&argv, "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
+ ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu);
- if (tun)
- {
- msg(M_FATAL, "no tun support on AIX (canthappen)");
- }
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig failed");
- /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */
- argv_printf(&argv,
- "%s %s %s netmask %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
-
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig failed");
- tt->did_ifconfig = true;
-
- if (do_ipv6)
- {
- argv_printf(&argv,
- "%s %s inet6 %s/%d",
- IFCONFIG_PATH,
- actual,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig inet6 failed");
- }
- env_set_destroy(aix_es);
- }
+ env_set_destroy(aix_es);
+ }
#elif defined (_WIN32)
- {
- ASSERT(actual != NULL);
+ ASSERT(ifname != NULL);
- 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,
- print_in_addr_t(tt->adapter_netmask, 0, &gc));
- break;
+ if (tt->options.ip_win32_type == IPW32_SET_MANUAL)
+ {
+ msg(M_INFO,
+ "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)",
+ ifname, ifconfig_local,
+ print_in_addr_t(tt->adapter_netmask, 0, &gc));
+ }
+ else if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ || tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
+ {
+ /* Let the DHCP configure the interface. */
+ }
+ else if (tt->options.msg_channel)
+ {
+ do_address_service(true, AF_INET, tt);
+ do_dns_service(true, AF_INET, tt);
+ }
+ else if (tt->options.ip_win32_type == IPW32_SET_NETSH)
+ {
+ netsh_ifconfig(&tt->options, ifname, tt->local,
+ tt->adapter_netmask, NI_IP_NETMASK|NI_OPTIONS);
+ }
+ if (tt->options.msg_channel)
+ {
+ do_set_mtu_service(tt, AF_INET, tun_mtu);
+ }
+ else
+ {
+ windows_set_mtu(tt->adapter_index, AF_INET, tun_mtu);
+ }
+#else /* if defined(TARGET_LINUX) */
+ 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.");
+#endif /* if defined(TARGET_LINUX) */
- case IPW32_SET_NETSH:
- netsh_ifconfig(&tt->options,
- actual,
- tt->local,
- tt->adapter_netmask,
- NI_IP_NETMASK|NI_OPTIONS);
+#if !defined(TARGET_LINUX)
+ gc_free(&gc);
+ argv_free(&argv);
+#endif
+}
- break;
- }
- tt->did_ifconfig = true;
- }
+/* execute the ifconfig command through the shell */
+void
+do_ifconfig(struct tuntap *tt, const char *ifname, int tun_mtu,
+ const struct env_set *es, openvpn_net_ctx_t *ctx)
+{
+ msg(D_LOW, "do_ifconfig, ipv4=%d, ipv6=%d", tt->did_ifconfig_setup,
+ tt->did_ifconfig_ipv6_setup);
- if (do_ipv6)
- {
- 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
- {
- /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */
- char iface[64];
- openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index );
- argv_printf(&argv,
- "%s%sc interface ipv6 set address %s %s store=active",
- get_win_sys_path(),
- NETSH_PATH_SUFFIX,
- 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);
- }
+#ifdef ENABLE_MANAGEMENT
+ if (management)
+ {
+ management_set_state(management,
+ OPENVPN_STATE_ASSIGN_IP,
+ NULL,
+ &tt->local,
+ &tt->local_ipv6,
+ NULL,
+ NULL);
+ }
+#endif
- /* explicit route needed */
- if (tt->options.ip_win32_type != IPW32_SET_MANUAL)
- {
- add_route_connected_v6_net(tt, es);
- }
- }
-#else /* if defined(TARGET_LINUX) */
- 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.");
-#endif /* if defined(TARGET_LINUX) */
- argv_reset(&argv);
+ if (tt->did_ifconfig_setup)
+ {
+ do_ifconfig_ipv4(tt, ifname, tun_mtu, es, ctx);
}
- gc_free(&gc);
+
+ if (tt->did_ifconfig_ipv6_setup)
+ {
+ do_ifconfig_ipv6(tt, ifname, tun_mtu, es, ctx);
+ }
+
+ /* release resources potentially allocated during interface setup */
+ net_ctx_free(ctx);
}
static void
@@ -1913,13 +1815,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
}
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt)
- {
- close_tun_generic(tt);
- free(tt);
- }
+ ASSERT(tt);
+
+ close_tun_generic(tt);
+ free(tt);
}
int
@@ -2065,12 +1966,14 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
ASSERT(0);
}
-#endif /* !PENDANTIC */
+#endif /* !PEDANTIC */
#ifdef ENABLE_FEATURE_TUN_PERSIST
void
-tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
+tuncfg(const char *dev, const char *dev_type, const char *dev_node,
+ int persist_mode, const char *username, const char *groupname,
+ const struct tuntap_options *options, openvpn_net_ctx_t *ctx)
{
struct tuntap *tt;
@@ -2109,86 +2012,95 @@ tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_
msg(M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", groupname, dev);
}
}
- close_tun(tt);
+ close_tun(tt, ctx);
msg(M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF"));
}
#endif /* ENABLE_FEATURE_TUN_PERSIST */
-void
-close_tun(struct tuntap *tt)
+static void
+undo_ifconfig_ipv4(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt)
+#if defined(TARGET_LINUX)
+ int netbits = netmask_to_netbits2(tt->remote_netmask);
+
+ if (is_tun_p2p(tt))
+ {
+ if (net_addr_ptp_v4_del(ctx, tt->actual_name, &tt->local,
+ &tt->remote_netmask) < 0)
+ {
+ msg(M_WARN, "Linux can't del IP from iface %s",
+ tt->actual_name);
+ }
+ }
+ else
{
- if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig)
+ if (net_addr_v4_del(ctx, tt->actual_name, &tt->local, netbits) < 0)
{
- struct argv argv = argv_new();
- struct gc_arena gc = gc_new();
+ msg(M_WARN, "Linux can't del IP from iface %s",
+ tt->actual_name);
+ }
+ }
+#else /* ifndef TARGET_LINUX */
+ struct argv argv = argv_new();
-#ifdef ENABLE_IPROUTE
- if (is_tun_p2p(tt))
- {
- argv_printf(&argv,
- "%s addr del dev %s local %s peer %s",
- iproute_path,
- tt->actual_name,
- print_in_addr_t(tt->local, 0, &gc),
- print_in_addr_t(tt->remote_netmask, 0, &gc)
- );
- }
- else
- {
- argv_printf(&argv,
- "%s addr del dev %s %s/%d",
- iproute_path,
- tt->actual_name,
- print_in_addr_t(tt->local, 0, &gc),
- netmask_to_netbits2(tt->remote_netmask)
- );
- }
-#else /* ifdef ENABLE_IPROUTE */
- argv_printf(&argv,
- "%s %s 0.0.0.0",
- IFCONFIG_PATH,
- tt->actual_name
- );
-#endif /* ifdef ENABLE_IPROUTE */
-
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "Linux ip addr del failed");
-
- if (tt->did_ifconfig_ipv6_setup)
- {
- const char *ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc);
-
-#ifdef ENABLE_IPROUTE
- argv_printf(&argv, "%s -6 addr del %s/%d dev %s",
- iproute_path,
- ifconfig_ipv6_local,
- tt->netbits_ipv6,
- tt->actual_name
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "Linux ip -6 addr del failed");
-#else /* ifdef ENABLE_IPROUTE */
- argv_printf(&argv,
- "%s %s del %s/%d",
- IFCONFIG_PATH,
- tt->actual_name,
- ifconfig_ipv6_local,
- tt->netbits_ipv6
- );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "Linux ifconfig inet6 del failed");
-#endif
- }
+ argv_printf(&argv, "%s %s 0.0.0.0", IFCONFIG_PATH, tt->actual_name);
+
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0, "Generic ip addr del failed");
+
+ argv_free(&argv);
+#endif /* ifdef TARGET_LINUX */
+}
- argv_reset(&argv);
- gc_free(&gc);
+static void
+undo_ifconfig_ipv6(struct tuntap *tt, openvpn_net_ctx_t *ctx)
+{
+#if defined(TARGET_LINUX)
+ if (net_addr_v6_del(ctx, tt->actual_name, &tt->local_ipv6,
+ tt->netbits_ipv6) < 0)
+ {
+ msg(M_WARN, "Linux can't del IPv6 from iface %s", tt->actual_name);
+ }
+#else /* ifndef TARGET_LINUX */
+ struct gc_arena gc = gc_new();
+ const char *ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, gc);
+ struct argv argv = argv_new();
+
+ argv_printf(&argv, "%s %s del %s/%d", IFCONFIG_PATH, tt->actual_name,
+ ifconfig_ipv6_local, tt->netbits_ipv6);
+
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0, "Linux ip -6 addr del failed");
+
+ argv_free(&argv);
+ gc_free(&gc);
+#endif /* ifdef TARGET_LINUX */
+}
+
+void
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
+{
+ ASSERT(tt);
+
+ if (tt->type != DEV_TYPE_NULL)
+ {
+ if (tt->did_ifconfig_setup)
+ {
+ undo_ifconfig_ipv4(tt, ctx);
}
- close_tun_generic(tt);
- free(tt);
+
+ if (tt->did_ifconfig_ipv6_setup)
+ {
+ undo_ifconfig_ipv6(tt, ctx);
+ }
+
+ /* release resources potentially allocated during undo */
+ net_ctx_reset(ctx);
}
+
+ close_tun_generic(tt);
+ free(tt);
}
int
@@ -2446,57 +2358,54 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
static void
solaris_close_tun(struct tuntap *tt)
{
- if (tt)
+ /* IPv6 interfaces need to be 'manually' de-configured */
+ if (tt->did_ifconfig_ipv6_setup)
{
- /* IPv6 interfaces need to be 'manually' de-configured */
- if (tt->did_ifconfig_ipv6_setup)
+ struct argv argv = argv_new();
+ argv_printf( &argv, "%s %s inet6 unplumb",
+ IFCONFIG_PATH, tt->actual_name );
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
+ argv_free(&argv);
+ }
+
+ if (tt->ip_fd >= 0)
+ {
+ struct lifreq ifr;
+ CLEAR(ifr);
+ strncpynt(ifr.lifr_name, tt->actual_name, sizeof(ifr.lifr_name));
+
+ if (ioctl(tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0)
{
- struct argv argv = argv_new();
- argv_printf( &argv, "%s %s inet6 unplumb",
- IFCONFIG_PATH, tt->actual_name );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
- argv_reset(&argv);
+ msg(M_WARN | M_ERRNO, "Can't get iface flags");
}
- if (tt->ip_fd >= 0)
+ if (ioctl(tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0)
{
- struct lifreq ifr;
- CLEAR(ifr);
- strncpynt(ifr.lifr_name, tt->actual_name, sizeof(ifr.lifr_name));
-
- if (ioctl(tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0)
- {
- msg(M_WARN | M_ERRNO, "Can't get iface flags");
- }
-
- if (ioctl(tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0)
- {
- msg(M_WARN | M_ERRNO, "Can't get multiplexor id");
- }
-
- if (tt->type == DEV_TYPE_TAP)
- {
- if (ioctl(tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0)
- {
- msg(M_WARN | M_ERRNO, "Can't unlink interface(arp)");
- }
- }
+ msg(M_WARN | M_ERRNO, "Can't get multiplexor id");
+ }
- if (ioctl(tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0)
+ if (tt->type == DEV_TYPE_TAP)
+ {
+ if (ioctl(tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0)
{
- msg(M_WARN | M_ERRNO, "Can't unlink interface(ip)");
+ msg(M_WARN | M_ERRNO, "Can't unlink interface(arp)");
}
-
- close(tt->ip_fd);
- tt->ip_fd = -1;
}
- if (tt->fd >= 0)
+ if (ioctl(tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0)
{
- close(tt->fd);
- tt->fd = -1;
+ msg(M_WARN | M_ERRNO, "Can't unlink interface(ip)");
}
+
+ close(tt->ip_fd);
+ tt->ip_fd = -1;
+ }
+
+ if (tt->fd >= 0)
+ {
+ close(tt->fd);
+ tt->fd = -1;
}
}
@@ -2504,20 +2413,19 @@ solaris_close_tun(struct tuntap *tt)
* Close TUN device.
*/
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt)
- {
- solaris_close_tun(tt);
+ ASSERT(tt);
- if (tt->actual_name)
- {
- free(tt->actual_name);
- }
+ solaris_close_tun(tt);
- clear_tuntap(tt);
- free(tt);
+ if (tt->actual_name)
+ {
+ free(tt->actual_name);
}
+
+ clear_tuntap(tt);
+ free(tt);
}
static void
@@ -2541,9 +2449,9 @@ solaris_error_close(struct tuntap *tt, const struct env_set *es,
argv_msg(M_INFO, &argv);
openvpn_execve_check(&argv, es, 0, "Solaris ifconfig unplumb failed");
- close_tun(tt);
+ close_tun(tt, NULL);
msg(M_FATAL, "Solaris ifconfig failed");
- argv_reset(&argv);
+ argv_free(&argv);
}
int
@@ -2604,33 +2512,34 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
*/
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
+ ASSERT(tt);
+
/* only *TAP* devices need destroying, tun devices auto-self-destruct
*/
- if (tt && (tt->type == DEV_TYPE_TUN || tt->persistent_if ) )
+ if (tt->type == DEV_TYPE_TUN || tt->persistent_if)
{
close_tun_generic(tt);
free(tt);
+ return;
}
- else if (tt)
- {
- struct gc_arena gc = gc_new();
- struct argv argv = argv_new();
- /* setup command, close tun dev (clears tt->actual_name!), run command
- */
+ struct argv argv = argv_new();
- argv_printf(&argv, "%s %s destroy",
- IFCONFIG_PATH, tt->actual_name);
+ /* setup command, close tun dev (clears tt->actual_name!), run command
+ */
- close_tun_generic(tt);
+ argv_printf(&argv, "%s %s destroy",
+ IFCONFIG_PATH, tt->actual_name);
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)");
+ close_tun_generic(tt);
- free(tt);
- }
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)");
+
+ free(tt);
+ argv_free(&argv);
}
int
@@ -2686,36 +2595,37 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
/* the current way OpenVPN handles tun devices on NetBSD leads to
* lingering tunX interfaces after close -> for a full cleanup, they
- * need to be explicitely destroyed
+ * need to be explicitly destroyed
*/
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
+ ASSERT(tt);
+
/* only tun devices need destroying, tap devices auto-self-destruct
*/
- if (tt && ( tt->type != DEV_TYPE_TUN || tt->persistent_if ) )
+ if (tt->type != DEV_TYPE_TUN || tt->persistent_if)
{
close_tun_generic(tt);
free(tt);
+ return;
}
- else if (tt)
- {
- struct gc_arena gc = gc_new();
- struct argv argv = argv_new();
- /* setup command, close tun dev (clears tt->actual_name!), run command
- */
+ struct argv argv = argv_new();
- argv_printf(&argv, "%s %s destroy",
- IFCONFIG_PATH, tt->actual_name);
+ /* setup command, close tun dev (clears tt->actual_name!), run command
+ */
- close_tun_generic(tt);
+ argv_printf(&argv, "%s %s destroy",
+ IFCONFIG_PATH, tt->actual_name);
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "NetBSD 'destroy tun interface' failed (non-critical)");
+ close_tun_generic(tt);
- free(tt);
- }
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0, "NetBSD 'destroy tun interface' failed (non-critical)");
+
+ free(tt);
+ argv_free(&argv);
}
static inline int
@@ -2829,30 +2739,34 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
* we need to call "ifconfig ... destroy" for cleanup
*/
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt && tt->persistent_if) /* keep pre-existing if around */
+ ASSERT(tt);
+
+ if (tt->persistent_if) /* keep pre-existing if around */
{
close_tun_generic(tt);
free(tt);
+ return;
}
- else if (tt) /* close and destroy */
- {
- struct argv argv = argv_new();
- /* setup command, close tun dev (clears tt->actual_name!), run command
- */
+ /* close and destroy */
+ struct argv argv = argv_new();
- argv_printf(&argv, "%s %s destroy",
- IFCONFIG_PATH, tt->actual_name);
+ /* setup command, close tun dev (clears tt->actual_name!), run command
+ */
- close_tun_generic(tt);
+ argv_printf(&argv, "%s %s destroy",
+ IFCONFIG_PATH, tt->actual_name);
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "FreeBSD 'destroy tun interface' failed (non-critical)");
+ close_tun_generic(tt);
- free(tt);
- }
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0,
+ "FreeBSD 'destroy tun interface' failed (non-critical)");
+
+ free(tt);
+ argv_free(&argv);
}
int
@@ -2941,13 +2855,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
}
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt)
- {
- close_tun_generic(tt);
- free(tt);
- }
+ ASSERT(tt);
+
+ close_tun_generic(tt);
+ free(tt);
}
int
@@ -3037,14 +2950,16 @@ utun_open_helper(struct ctl_info ctlInfo, int utunnum)
if (fd < 0)
{
- msg(M_INFO | M_ERRNO, "Opening utun (socket(SYSPROTO_CONTROL))");
+ msg(M_INFO | M_ERRNO, "Opening utun%d failed (socket(SYSPROTO_CONTROL))",
+ utunnum);
return -2;
}
if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
{
close(fd);
- msg(M_INFO | M_ERRNO, "Opening utun (ioctl(CTLIOCGINFO))");
+ msg(M_INFO | M_ERRNO, "Opening utun%d failed (ioctl(CTLIOCGINFO))",
+ utunnum);
return -2;
}
@@ -3062,7 +2977,8 @@ utun_open_helper(struct ctl_info ctlInfo, int utunnum)
if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
{
- msg(M_INFO | M_ERRNO, "Opening utun (connect(AF_SYS_CONTROL))");
+ msg(M_INFO | M_ERRNO, "Opening utun%d failed (connect(AF_SYS_CONTROL))",
+ utunnum);
close(fd);
return -1;
}
@@ -3105,11 +3021,18 @@ open_darwin_utun(const char *dev, const char *dev_type, const char *dev_node, st
/* try to open first available utun device if no specific utun is requested */
if (utunnum == -1)
{
- for (utunnum = 0; utunnum<255; utunnum++)
+ for (utunnum = 0; utunnum < 255; utunnum++)
{
+ char ifname[20];
+ /* if the interface exists silently skip it */
+ ASSERT(snprintf(ifname, sizeof(ifname), "utun%d", utunnum) > 0);
+ if (if_nametoindex(ifname))
+ {
+ continue;
+ }
fd = utun_open_helper(ctlInfo, utunnum);
/* Break if the fd is valid,
- * or if early initalization failed (-2) */
+ * or if early initialization failed (-2) */
if (fd !=-1)
{
break;
@@ -3198,29 +3121,28 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
}
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt)
- {
- struct gc_arena gc = gc_new();
- struct argv argv = argv_new();
+ ASSERT(tt);
- if (tt->did_ifconfig_ipv6_setup)
- {
- const char *ifconfig_ipv6_local =
- print_in6_addr(tt->local_ipv6, 0, &gc);
+ struct gc_arena gc = gc_new();
+ struct argv argv = argv_new();
- argv_printf(&argv, "%s delete -inet6 %s",
- ROUTE_PATH, ifconfig_ipv6_local );
- argv_msg(M_INFO, &argv);
- openvpn_execve_check(&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)");
- }
+ if (tt->did_ifconfig_ipv6_setup)
+ {
+ const char *ifconfig_ipv6_local =
+ print_in6_addr(tt->local_ipv6, 0, &gc);
- close_tun_generic(tt);
- free(tt);
- argv_reset(&argv);
- gc_free(&gc);
+ argv_printf(&argv, "%s delete -inet6 %s",
+ ROUTE_PATH, ifconfig_ipv6_local );
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)");
}
+
+ close_tun_generic(tt);
+ free(tt);
+ argv_free(&argv);
+ gc_free(&gc);
}
int
@@ -3323,6 +3245,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
env_set_add( es, "ODMDIR=/etc/objrepos" );
openvpn_execve_check(&argv, es, S_FATAL, "AIX 'create tun interface' failed");
env_set_destroy(es);
+ argv_free(&argv);
}
else
{
@@ -3346,17 +3269,13 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
/* tap devices need to be manually destroyed on AIX
*/
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- struct gc_arena gc = gc_new();
+ ASSERT(tt);
+
struct argv argv = argv_new();
struct env_set *es = env_set_create(NULL);
- if (!tt)
- {
- return;
- }
-
/* persistent devices need IP address unconfig, others need destroyal
*/
if (tt->persistent_if)
@@ -3377,6 +3296,7 @@ close_tun(struct tuntap *tt)
free(tt);
env_set_destroy(es);
+ argv_free(&argv);
}
int
@@ -3393,6 +3313,22 @@ read_tun(struct tuntap *tt, uint8_t *buf, int len)
#elif defined(_WIN32)
+static const char *
+print_windows_driver(enum windows_driver_type windows_driver)
+{
+ switch (windows_driver)
+ {
+ case WINDOWS_DRIVER_TAP_WINDOWS6:
+ return "tap-windows6";
+
+ case WINDOWS_DRIVER_WINTUN:
+ return "wintun";
+
+ default:
+ return "unspecified";
+ }
+}
+
int
tun_read_queue(struct tuntap *tt, int maxsize)
{
@@ -3604,7 +3540,123 @@ tun_finalize(
return ret;
}
-const struct tap_reg *
+static const struct device_instance_id_interface *
+get_device_instance_id_interface(struct gc_arena *gc)
+{
+ HDEVINFO dev_info_set;
+ DWORD err;
+ struct device_instance_id_interface *first = NULL;
+ struct device_instance_id_interface *last = NULL;
+
+ dev_info_set = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
+ if (dev_info_set == INVALID_HANDLE_VALUE)
+ {
+ err = GetLastError();
+ msg(M_FATAL, "Error [%u] opening device information set key: %s", (unsigned int)err, strerror_win32(err, gc));
+ }
+
+ for (DWORD i = 0;; ++i)
+ {
+ SP_DEVINFO_DATA device_info_data;
+ BOOL res;
+ HKEY dev_key;
+ char net_cfg_instance_id_string[] = "NetCfgInstanceId";
+ char net_cfg_instance_id[256];
+ char device_instance_id[256];
+ DWORD len;
+ DWORD data_type;
+ LONG status;
+ ULONG dev_interface_list_size;
+ CONFIGRET cr;
+ struct buffer dev_interface_list;
+
+ ZeroMemory(&device_info_data, sizeof(SP_DEVINFO_DATA));
+ device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
+ res = SetupDiEnumDeviceInfo(dev_info_set, i, &device_info_data);
+ if (!res)
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ {
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ dev_key = SetupDiOpenDevRegKey(dev_info_set, &device_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+ if (dev_key == INVALID_HANDLE_VALUE)
+ {
+ continue;
+ }
+
+ len = sizeof(net_cfg_instance_id);
+ data_type = REG_SZ;
+ status = RegQueryValueEx(dev_key,
+ net_cfg_instance_id_string,
+ NULL,
+ &data_type,
+ net_cfg_instance_id,
+ &len);
+ if (status != ERROR_SUCCESS)
+ {
+ goto next;
+ }
+
+ len = sizeof(device_instance_id);
+ res = SetupDiGetDeviceInstanceId(dev_info_set, &device_info_data, device_instance_id, len, &len);
+ if (!res)
+ {
+ goto next;
+ }
+
+ cr = CM_Get_Device_Interface_List_Size(&dev_interface_list_size,
+ (LPGUID)&GUID_DEVINTERFACE_NET,
+ device_instance_id,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+
+ if (cr != CR_SUCCESS)
+ {
+ goto next;
+ }
+
+ dev_interface_list = alloc_buf_gc(dev_interface_list_size, gc);
+ cr = CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_NET, device_instance_id,
+ BPTR(&dev_interface_list),
+ dev_interface_list_size,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+ if (cr != CR_SUCCESS)
+ {
+ goto next;
+ }
+
+ struct device_instance_id_interface *dev_if;
+ ALLOC_OBJ_CLEAR_GC(dev_if, struct device_instance_id_interface, gc);
+ dev_if->net_cfg_instance_id = string_alloc(net_cfg_instance_id, gc);
+ dev_if->device_interface_list = string_alloc(BSTR(&dev_interface_list), gc);
+
+ /* link into return list */
+ if (!first)
+ {
+ first = dev_if;
+ }
+ if (last)
+ {
+ last->next = dev_if;
+ }
+ last = dev_if;
+
+next:
+ RegCloseKey(dev_key);
+ }
+
+ SetupDiDestroyDeviceInfoList(dev_info_set);
+
+ return first;
+}
+
+static const struct tap_reg *
get_tap_reg(struct gc_arena *gc)
{
HKEY adapter_key;
@@ -3700,12 +3752,24 @@ get_tap_reg(struct gc_arena *gc)
if (status == ERROR_SUCCESS && data_type == REG_SZ)
{
- if (!strcmp(component_id, TAP_WIN_COMPONENT_ID) ||
- !strcmp(component_id, "root\\" TAP_WIN_COMPONENT_ID))
+ /* Is this adapter supported? */
+ enum windows_driver_type windows_driver = WINDOWS_DRIVER_UNSPECIFIED;
+ if (strcasecmp(component_id, TAP_WIN_COMPONENT_ID) == 0
+ || strcasecmp(component_id, "root\\" TAP_WIN_COMPONENT_ID) == 0)
+ {
+ windows_driver = WINDOWS_DRIVER_TAP_WINDOWS6;
+ }
+ else if (strcasecmp(component_id, WINTUN_COMPONENT_ID) == 0)
+ {
+ windows_driver = WINDOWS_DRIVER_WINTUN;
+ }
+
+ if (windows_driver != WINDOWS_DRIVER_UNSPECIFIED)
{
struct tap_reg *reg;
ALLOC_OBJ_CLEAR_GC(reg, struct tap_reg, gc);
reg->guid = string_alloc(net_cfg_instance_id, gc);
+ reg->windows_driver = windows_driver;
/* link into return list */
if (!first)
@@ -3729,7 +3793,7 @@ get_tap_reg(struct gc_arena *gc)
return first;
}
-const struct panel_reg *
+static const struct panel_reg *
get_panel_reg(struct gc_arena *gc)
{
LONG status;
@@ -3936,7 +4000,7 @@ show_tap_win_adapters(int msglev, int warnlev)
const struct tap_reg *tap_reg = get_tap_reg(&gc);
const struct panel_reg *panel_reg = get_panel_reg(&gc);
- msg(msglev, "Available TAP-WIN32 adapters [name, GUID]:");
+ msg(msglev, "Available TAP-WIN32 / Wintun adapters [name, GUID, driver]:");
/* loop through each TAP-Windows adapter registry entry */
for (tr = tap_reg; tr != NULL; tr = tr->next)
@@ -3948,7 +4012,7 @@ show_tap_win_adapters(int msglev, int warnlev)
{
if (!strcmp(tr->guid, pr->guid))
{
- msg(msglev, "'%s' %s", pr->name, tr->guid);
+ msg(msglev, "'%s' %s %s", pr->name, tr->guid, print_windows_driver(tr->windows_driver));
++links;
}
}
@@ -3998,10 +4062,10 @@ show_tap_win_adapters(int msglev, int warnlev)
}
/*
- * Confirm that GUID is a TAP-Windows adapter.
+ * Lookup a TAP-Windows or Wintun adapter by GUID.
*/
-static bool
-is_tap_win(const char *guid, const struct tap_reg *tap_reg)
+static const struct tap_reg *
+get_adapter_by_guid(const char *guid, const struct tap_reg *tap_reg)
{
const struct tap_reg *tr;
@@ -4009,11 +4073,11 @@ is_tap_win(const char *guid, const struct tap_reg *tap_reg)
{
if (guid && !strcmp(tr->guid, guid))
{
- return true;
+ return tr;
}
}
- return false;
+ return NULL;
}
static const char *
@@ -4032,16 +4096,16 @@ guid_to_name(const char *guid, const struct panel_reg *panel_reg)
return NULL;
}
-static const char *
-name_to_guid(const char *name, const struct tap_reg *tap_reg, const struct panel_reg *panel_reg)
+static const struct tap_reg *
+get_adapter_by_name(const char *name, const struct tap_reg *tap_reg, const struct panel_reg *panel_reg)
{
const struct panel_reg *pr;
for (pr = panel_reg; pr != NULL; pr = pr->next)
{
- if (name && !strcmp(pr->name, name) && is_tap_win(pr->guid, tap_reg))
+ if (name && !strcmp(pr->name, name))
{
- return pr->guid;
+ return get_adapter_by_guid(pr->guid, tap_reg);
}
}
@@ -4053,7 +4117,7 @@ at_least_one_tap_win(const struct tap_reg *tap_reg)
{
if (!tap_reg)
{
- msg(M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter.");
+ msg(M_FATAL, "There are no TAP-Windows nor Wintun adapters on this system. You should be able to create an adapter by using tapctl.exe utility.");
}
}
@@ -4067,6 +4131,7 @@ get_unspecified_device_guid(const int device_number,
int actual_name_size,
const struct tap_reg *tap_reg_src,
const struct panel_reg *panel_reg_src,
+ enum windows_driver_type *windows_driver,
struct gc_arena *gc)
{
const struct tap_reg *tap_reg = tap_reg_src;
@@ -4116,23 +4181,29 @@ get_unspecified_device_guid(const int device_number,
/* Save GUID for return value */
ret = alloc_buf_gc(256, gc);
buf_printf(&ret, "%s", tap_reg->guid);
+ if (windows_driver != NULL)
+ {
+ *windows_driver = tap_reg->windows_driver;
+ }
return BSTR(&ret);
}
/*
* Lookup a --dev-node adapter name in the registry
- * returning the GUID and optional actual_name.
+ * returning the GUID and optional actual_name and device type
*/
static const char *
get_device_guid(const char *name,
char *actual_name,
int actual_name_size,
+ enum windows_driver_type *windows_driver,
const struct tap_reg *tap_reg,
const struct panel_reg *panel_reg,
struct gc_arena *gc)
{
struct buffer ret = alloc_buf_gc(256, gc);
struct buffer actual = clear_buf();
+ const struct tap_reg *tr;
/* Make sure we have at least one TAP adapter */
if (!tap_reg)
@@ -4148,7 +4219,8 @@ get_device_guid(const char *name,
}
/* Check if GUID was explicitly specified as --dev-node parameter */
- if (is_tap_win(name, tap_reg))
+ tr = get_adapter_by_guid(name, tap_reg);
+ if (tr)
{
const char *act = guid_to_name(name, panel_reg);
buf_printf(&ret, "%s", name);
@@ -4160,16 +4232,24 @@ get_device_guid(const char *name,
{
buf_printf(&actual, "%s", name);
}
+ if (windows_driver)
+ {
+ *windows_driver = tr->windows_driver;
+ }
return BSTR(&ret);
}
/* Lookup TAP adapter in network connections list */
{
- const char *guid = name_to_guid(name, tap_reg, panel_reg);
- if (guid)
+ tr = get_adapter_by_name(name, tap_reg, panel_reg);
+ if (tr)
{
buf_printf(&actual, "%s", name);
- buf_printf(&ret, "%s", guid);
+ if (windows_driver)
+ {
+ *windows_driver = tr->windows_driver;
+ }
+ buf_printf(&ret, "%s", tr->guid);
return BSTR(&ret);
}
}
@@ -4649,8 +4729,7 @@ get_adapter_index_method_1(const char *guid)
DWORD index;
ULONG aindex;
wchar_t wbuf[256];
- swprintf(wbuf, SIZE(wbuf), L"\\DEVICE\\TCPIP_%S", guid);
- wbuf [SIZE(wbuf) - 1] = 0;
+ openvpn_swprintf(wbuf, SIZE(wbuf), L"\\DEVICE\\TCPIP_%S", guid);
if (GetAdapterIndex(wbuf, &aindex) != NO_ERROR)
{
index = TUN_ADAPTER_INDEX_INVALID;
@@ -4714,11 +4793,14 @@ get_adapter_index_flexible(const char *name) /* actual name or GUID */
{
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 == TUN_ADAPTER_INDEX_INVALID)
+ const struct tap_reg *tr = get_adapter_by_name(name, tap_reg, panel_reg);
+ if (tr)
{
- index = get_adapter_index_method_2(guid);
+ index = get_adapter_index_method_1(tr->guid);
+ if (index == TUN_ADAPTER_INDEX_INVALID)
+ {
+ index = get_adapter_index_method_2(tr->guid);
+ }
}
}
if (index == TUN_ADAPTER_INDEX_INVALID)
@@ -4851,7 +4933,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, actual_buffer, sizeof(actual_buffer), tap_reg, panel_reg, &gc);
+ device_guid = get_device_guid(dev_node, actual_buffer, sizeof(actual_buffer), NULL, tap_reg, panel_reg, &gc);
if (!device_guid)
{
@@ -4894,6 +4976,7 @@ tap_allow_nonadmin_access(const char *dev_node)
sizeof(actual_buffer),
tap_reg,
panel_reg,
+ NULL,
&gc);
if (!device_guid)
@@ -5049,19 +5132,19 @@ ipconfig_register_dns(const struct env_set *es)
msg(D_TUNTAP_INFO, "Start ipconfig commands for register-dns...");
netcmd_semaphore_lock();
- argv_printf(&argv, "%s%sc /flushdns",
+ argv_printf(&argv, "%s%s /flushdns",
get_win_sys_path(),
WIN_IPCONFIG_PATH_SUFFIX);
argv_msg(D_TUNTAP_INFO, &argv);
openvpn_execve_check(&argv, es, 0, err);
- argv_reset(&argv);
+ argv_free(&argv);
- argv_printf(&argv, "%s%sc /registerdns",
+ argv_printf(&argv, "%s%s /registerdns",
get_win_sys_path(),
WIN_IPCONFIG_PATH_SUFFIX);
argv_msg(D_TUNTAP_INFO, &argv);
openvpn_execve_check(&argv, es, 0, err);
- argv_reset(&argv);
+ argv_free(&argv);
netcmd_semaphore_release();
msg(D_TUNTAP_INFO, "End ipconfig commands for register-dns...");
@@ -5170,8 +5253,8 @@ netsh_set_dns6_servers(const struct in6_addr *addr_list,
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";
+ "%s%s interface ipv6 set dns %s static %s"
+ : "%s%s 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));
@@ -5186,7 +5269,7 @@ netsh_set_dns6_servers(const struct in6_addr *addr_list,
netsh_command(&argv, 1, (i==0) ? M_FATAL : M_NONFATAL);
}
- argv_reset(&argv);
+ argv_free(&argv);
gc_free(&gc);
}
@@ -5201,6 +5284,7 @@ netsh_ifconfig_options(const char *type,
struct gc_arena gc = gc_new();
struct argv argv = argv_new();
bool delete_first = false;
+ bool is_dns = !strcmp(type, "dns");
/* first check if we should delete existing DNS/WINS settings from TAP interface */
if (test_first)
@@ -5218,7 +5302,7 @@ netsh_ifconfig_options(const char *type,
/* delete existing DNS/WINS settings from TAP interface */
if (delete_first)
{
- argv_printf(&argv, "%s%sc interface ip delete %s %s all",
+ argv_printf(&argv, "%s%s interface ip delete %s %s all",
get_win_sys_path(),
NETSH_PATH_SUFFIX,
type,
@@ -5235,8 +5319,8 @@ netsh_ifconfig_options(const char *type,
if (delete_first || !test_first || !ip_addr_member_of(addr_list[i], current))
{
const char *fmt = count ?
- "%s%sc interface ip add %s %s %s"
- : "%s%sc interface ip set %s %s static %s";
+ "%s%s interface ip add %s %s %s"
+ : "%s%s interface ip set %s %s static %s";
argv_printf(&argv, fmt,
get_win_sys_path(),
@@ -5244,6 +5328,14 @@ netsh_ifconfig_options(const char *type,
type,
flex_name,
print_in_addr_t(addr_list[i], 0, &gc));
+
+ /* disable slow address validation on Windows 7 and higher */
+ /* only for DNS */
+ if (is_dns && win32_version_info() >= WIN_7)
+ {
+ argv_printf_cat(&argv, "%s", "validate=no");
+ }
+
netsh_command(&argv, 2, M_FATAL);
++count;
@@ -5258,7 +5350,7 @@ netsh_ifconfig_options(const char *type,
}
}
- argv_reset(&argv);
+ argv_free(&argv);
gc_free(&gc);
}
@@ -5312,7 +5404,7 @@ netsh_ifconfig(const struct tuntap_options *to,
else
{
/* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
- argv_printf(&argv, "%s%sc interface ip set address %s static %s %s",
+ argv_printf(&argv, "%s%s interface ip set address %s static %s %s",
get_win_sys_path(),
NETSH_PATH_SUFFIX,
flex_name,
@@ -5349,7 +5441,7 @@ netsh_ifconfig(const struct tuntap_options *to,
BOOL_CAST(flags & NI_TEST_FIRST));
}
- argv_reset(&argv);
+ argv_free(&argv);
gc_free(&gc);
}
@@ -5360,21 +5452,20 @@ netsh_enable_dhcp(const char *actual_name)
/* example: netsh interface ip set address my-tap dhcp */
argv_printf(&argv,
- "%s%sc interface ip set address %s dhcp",
+ "%s%s interface ip set address %s dhcp",
get_win_sys_path(),
NETSH_PATH_SUFFIX,
actual_name);
netsh_command(&argv, 4, M_FATAL);
- argv_reset(&argv);
+ argv_free(&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();
@@ -5389,11 +5480,8 @@ service_enable_dhcp(const struct tuntap *tt)
.iface = { .index = tt->adapter_index, .name = "" }
};
- if (!WriteFile(pipe, &dhcp, sizeof(dhcp), &len, NULL)
- || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL))
+ if (!send_msg_iservice(pipe, &dhcp, sizeof(dhcp), &ack, "Enable_dhcp"))
{
- msg(M_WARN, "Enable_dhcp: could not talk to service: %s [%lu]",
- strerror_win32(GetLastError(), &gc), GetLastError());
goto out;
}
@@ -5413,6 +5501,45 @@ out:
return ret;
}
+static void
+windows_set_mtu(const int iface_index, const short family,
+ const int mtu)
+{
+ DWORD err = 0;
+ struct gc_arena gc = gc_new();
+ MIB_IPINTERFACE_ROW ipiface;
+ InitializeIpInterfaceEntry(&ipiface);
+ const char *family_name = (family == AF_INET6) ? "IPv6" : "IPv4";
+ ipiface.Family = family;
+ ipiface.InterfaceIndex = iface_index;
+ if (family == AF_INET6 && mtu < 1280)
+ {
+ msg(M_INFO, "NOTE: IPv6 interface MTU < 1280 conflicts with IETF standards and might not work");
+ }
+
+ err = GetIpInterfaceEntry(&ipiface);
+ if (err == NO_ERROR)
+ {
+ if (family == AF_INET)
+ {
+ ipiface.SitePrefixLength = 0;
+ }
+ ipiface.NlMtu = mtu;
+ err = SetIpInterfaceEntry(&ipiface);
+ }
+
+ if (err != NO_ERROR)
+ {
+ msg(M_WARN, "TUN: Setting %s mtu failed: %s [status=%u if_index=%d]",
+ family_name, strerror_win32(err, &gc), err, iface_index);
+ }
+ else
+ {
+ msg(M_INFO, "%s MTU set to %d on interface %d using SetIpInterfaceEntry()", family_name, mtu, iface_index);
+ }
+}
+
+
/*
* Return a TAP name for netsh commands.
*/
@@ -5428,13 +5555,13 @@ netsh_get_id(const char *dev_node, struct gc_arena *gc)
if (dev_node)
{
- guid = get_device_guid(dev_node, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, gc);
+ guid = get_device_guid(dev_node, BPTR(&actual), BCAP(&actual), NULL, tap_reg, panel_reg, gc);
}
else
{
- guid = get_unspecified_device_guid(0, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, gc);
+ guid = get_unspecified_device_guid(0, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, NULL, gc);
- if (get_unspecified_device_guid(1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Windows adapter */
+ if (get_unspecified_device_guid(1, NULL, 0, tap_reg, panel_reg, NULL, gc)) /* ambiguous if more than one TAP-Windows adapter */
{
guid = NULL;
}
@@ -5556,6 +5683,75 @@ write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error)
buf_write(buf, str, len);
}
+/*
+ * RFC3397 states that multiple searchdomains are encoded as follows:
+ * - at start the length of the entire option is given
+ * - each subdomain is preceded by its length
+ * - each searchdomain is separated by a NUL character
+ * e.g. if you want "openvpn.net" and "duckduckgo.com" then you end up with
+ * 0x1D 0x7 openvpn 0x3 net 0x00 0x0A duckduckgo 0x3 com 0x00
+ */
+static void
+write_dhcp_search_str(struct buffer *buf, const int type, const char * const *str_array,
+ int array_len, bool *error)
+{
+ char tmp_buf[256];
+ int i;
+ int len = 0;
+ int label_length_pos;
+
+ for (i=0; i < array_len; i++)
+ {
+ const char *ptr = str_array[i];
+
+ if (strlen(ptr) + len + 1 > sizeof(tmp_buf))
+ {
+ *error = true;
+ msg(M_WARN, "write_dhcp_search_str: temp buffer overflow building DHCP options");
+ return;
+ }
+ /* Loop over all subdomains separated by a dot and replace the dot
+ with the length of the subdomain */
+
+ /* label_length_pos points to the byte to be replaced by the length
+ * of the following domain label */
+ label_length_pos = len++;
+
+ while (true)
+ {
+ if (*ptr == '.' || *ptr == '\0' )
+ {
+ tmp_buf[label_length_pos] = (len-label_length_pos)-1;
+ label_length_pos = len;
+ if (*ptr == '\0')
+ {
+ break;
+ }
+ }
+ tmp_buf[len++] = *ptr++;
+ }
+ /* And close off with an extra NUL char */
+ tmp_buf[len++] = 0;
+ }
+
+ if (!buf_safe(buf, 2 + len))
+ {
+ *error = true;
+ msg(M_WARN, "write_search_dhcp_str: buffer overflow building DHCP options");
+ return;
+ }
+ if (len > 255)
+ {
+ *error = true;
+ msg(M_WARN, "write_dhcp_search_str: search domain string must be <= 255 bytes");
+ return;
+ }
+
+ buf_write_u8(buf, type);
+ buf_write_u8(buf, len);
+ buf_write(buf, tmp_buf, len);
+}
+
static bool
build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o)
{
@@ -5580,6 +5776,13 @@ build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o)
write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error);
write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error);
+ if (o->domain_search_list_len > 0)
+ {
+ write_dhcp_search_str(buf, 119, o->domain_search_list,
+ o->domain_search_list_len,
+ &error);
+ }
+
/* the MS DHCP server option 'Disable Netbios-over-TCP/IP
* is implemented as vendor option 001, value 002.
* A value of 001 means 'leave NBT alone' which is the default */
@@ -5618,7 +5821,7 @@ fork_dhcp_action(struct tuntap *tt)
{
buf_printf(&cmd, " --dhcp-renew");
}
- buf_printf(&cmd, " --dhcp-internal %u", (unsigned int)tt->adapter_index);
+ buf_printf(&cmd, " --dhcp-internal %lu", tt->adapter_index);
fork_to_self(BSTR(&cmd));
gc_free(&gc);
@@ -5628,18 +5831,16 @@ fork_dhcp_action(struct tuntap *tt)
static void
register_dns_service(const struct tuntap *tt)
{
- DWORD len;
HANDLE msg_channel = tt->options.msg_channel;
ack_message_t ack;
struct gc_arena gc = gc_new();
message_header_t rdns = { msg_register_dns, sizeof(message_header_t), 0 };
- if (!WriteFile(msg_channel, &rdns, sizeof(rdns), &len, NULL)
- || !ReadFile(msg_channel, &ack, sizeof(ack), &len, NULL))
+ if (!send_msg_iservice(msg_channel, &rdns, sizeof(rdns), &ack, "Register_dns"))
{
- msg(M_WARN, "Register_dns: could not talk to service: %s [status=0x%lx]",
- strerror_win32(GetLastError(), &gc), GetLastError());
+ gc_free(&gc);
+ return;
}
else if (ack.error_number != NO_ERROR)
@@ -5656,6 +5857,46 @@ register_dns_service(const struct tuntap *tt)
gc_free(&gc);
}
+static bool
+service_register_ring_buffers(const struct tuntap *tt)
+{
+ HANDLE msg_channel = tt->options.msg_channel;
+ ack_message_t ack;
+ bool ret = true;
+ struct gc_arena gc = gc_new();
+
+ register_ring_buffers_message_t msg = {
+ .header = {
+ msg_register_ring_buffers,
+ sizeof(register_ring_buffers_message_t),
+ 0
+ },
+ .device = tt->hand,
+ .send_ring_handle = tt->wintun_send_ring_handle,
+ .receive_ring_handle = tt->wintun_receive_ring_handle,
+ .send_tail_moved = tt->rw_handle.read,
+ .receive_tail_moved = tt->rw_handle.write
+ };
+
+ if (!send_msg_iservice(msg_channel, &msg, sizeof(msg), &ack, "Register ring buffers"))
+ {
+ ret = false;
+ }
+ else if (ack.error_number != NO_ERROR)
+ {
+ msg(M_NONFATAL, "Register ring buffers failed using service: %s [status=0x%x]",
+ strerror_win32(ack.error_number, &gc), ack.error_number);
+ ret = false;
+ }
+ else
+ {
+ msg(M_INFO, "Ring buffers registered via service");
+ }
+
+ gc_free(&gc);
+ return ret;
+}
+
void
fork_register_dns_action(struct tuntap *tt)
{
@@ -5704,511 +5945,650 @@ dhcp_masq_addr(const in_addr_t local, const in_addr_t netmask, const int offset)
return htonl(dsa);
}
-void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+static void
+tuntap_get_version_info(const struct tuntap *tt)
{
- struct gc_arena gc = gc_new();
- char device_path[256];
- const char *device_guid = NULL;
+ ULONG info[3];
DWORD len;
- bool dhcp_masq = false;
- bool dhcp_masq_post = false;
-
- /*netcmd_semaphore_lock ();*/
-
- msg( M_INFO, "open_tun");
-
- if (tt->type == DEV_TYPE_NULL)
+ CLEAR(info);
+ if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_VERSION,
+ &info, sizeof(info),
+ &info, sizeof(info), &len, NULL))
{
- open_null(tt);
- gc_free(&gc);
- return;
+ msg(D_TUNTAP_INFO, "TAP-Windows Driver Version %d.%d %s",
+ (int)info[0],
+ (int)info[1],
+ (info[2] ? "(DEBUG)" : ""));
+
}
- else if (tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN)
+ if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR))
{
+ msg(M_FATAL, "ERROR: This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d -- If you recently upgraded your " PACKAGE_NAME " distribution, a reboot is probably required at this point to get Windows to see the new driver.",
+ TAP_WIN_MIN_MAJOR,
+ TAP_WIN_MIN_MINOR);
}
- else
+
+ /* usage of numeric constants is ugly, but this is really tied to
+ * *this* version of the driver
+ */
+ if (tt->type == DEV_TYPE_TUN
+ && info[0] == 9 && info[1] < 8)
{
- msg(M_FATAL|M_NOPREFIX, "Unknown virtual device type: '%s'", dev);
+ msg(M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will not work. Upgrade your Tap-Win32 driver.", (int)info[0], (int)info[1]);
}
- /*
- * Lookup the device name in the registry, using the --dev-node high level name.
+ /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy
*/
+ if (tt->type == DEV_TYPE_TUN
+ && info[0] == 9 && info[1] == 8)
{
- const struct tap_reg *tap_reg = get_tap_reg(&gc);
- const struct panel_reg *panel_reg = get_panel_reg(&gc);
- char actual_buffer[256];
-
- at_least_one_tap_win(tap_reg);
+ msg(M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade your Tap-Win32 driver.", (int)info[0], (int)info[1]);
+ }
+}
- if (dev_node)
- {
- /* Get the device GUID for the device specified with --dev-node. */
- device_guid = get_device_guid(dev_node, actual_buffer, sizeof(actual_buffer), tap_reg, panel_reg, &gc);
+static void
+tuntap_get_mtu(struct tuntap *tt)
+{
+ ULONG mtu = 0;
+ DWORD len;
+ if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_MTU,
+ &mtu, sizeof(mtu),
+ &mtu, sizeof(mtu), &len, NULL))
+ {
+ tt->post_open_mtu = (int)mtu;
+ msg(D_MTU_INFO, "TAP-Windows MTU=%d", (int)mtu);
+ }
+}
- if (!device_guid)
- {
- msg(M_FATAL, "TAP-Windows adapter '%s' not found", dev_node);
- }
+static void
+tuntap_set_ip_addr(struct tuntap *tt,
+ const char *device_guid,
+ bool dhcp_masq_post)
+{
+ struct gc_arena gc = gc_new();
+ const DWORD index = tt->adapter_index;
- /* Open Windows TAP-Windows adapter */
- openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s",
- USERMODEDEVICEDIR,
- device_guid,
- TAP_WIN_SUFFIX);
+ /* flush arp cache */
+ if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6
+ && index != TUN_ADAPTER_INDEX_INVALID)
+ {
+ DWORD status = -1;
- tt->hand = CreateFile(
- device_path,
- GENERIC_READ | GENERIC_WRITE,
- 0, /* was: FILE_SHARE_READ */
- 0,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
- 0
- );
+ if (tt->options.msg_channel)
+ {
+ ack_message_t ack;
+ flush_neighbors_message_t msg = {
+ .header = {
+ msg_flush_neighbors,
+ sizeof(flush_neighbors_message_t),
+ 0
+ },
+ .family = AF_INET,
+ .iface = {.index = index, .name = "" }
+ };
- if (tt->hand == INVALID_HANDLE_VALUE)
+ if (send_msg_iservice(tt->options.msg_channel, &msg, sizeof(msg),
+ &ack, "TUN"))
{
- msg(M_ERR, "CreateFile failed on TAP device: %s", device_path);
+ status = ack.error_number;
}
}
else
{
- int device_number = 0;
-
- /* Try opening all TAP devices until we find one available */
- while (true)
- {
- device_guid = get_unspecified_device_guid(device_number,
- actual_buffer,
- sizeof(actual_buffer),
- tap_reg,
- panel_reg,
- &gc);
-
- if (!device_guid)
- {
- msg(M_FATAL, "All TAP-Windows adapters on this system are currently in use.");
- }
-
- /* Open Windows TAP-Windows adapter */
- openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s",
- USERMODEDEVICEDIR,
- device_guid,
- TAP_WIN_SUFFIX);
-
- tt->hand = CreateFile(
- device_path,
- GENERIC_READ | GENERIC_WRITE,
- 0, /* was: FILE_SHARE_READ */
- 0,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
- 0
- );
-
- if (tt->hand == INVALID_HANDLE_VALUE)
- {
- msg(D_TUNTAP_INFO, "CreateFile failed on TAP device: %s", device_path);
- }
- else
- {
- break;
- }
-
- device_number++;
- }
+ status = FlushIpNetTable(index);
}
- /* translate high-level device name into a device instance
- * GUID using the registry */
- 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 */
- {
- ULONG info[3];
- CLEAR(info);
- if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_VERSION,
- &info, sizeof(info),
- &info, sizeof(info), &len, NULL))
+ if (status == NO_ERROR)
{
- msg(D_TUNTAP_INFO, "TAP-Windows Driver Version %d.%d %s",
- (int) info[0],
- (int) info[1],
- (info[2] ? "(DEBUG)" : ""));
-
+ msg(M_INFO, "Successful ARP Flush on interface [%lu] %s",
+ index,
+ device_guid);
}
- if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR))
+ else if (status != -1)
{
- msg(M_FATAL, "ERROR: This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d -- If you recently upgraded your " PACKAGE_NAME " distribution, a reboot is probably required at this point to get Windows to see the new driver.",
- TAP_WIN_MIN_MAJOR,
- TAP_WIN_MIN_MINOR);
+ msg(D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%lu] %s (status=%lu) : %s",
+ index,
+ device_guid,
+ status,
+ strerror_win32(status, &gc));
}
+ }
- /* usage of numeric constants is ugly, but this is really tied to
- * *this* version of the driver
- */
- if (tt->type == DEV_TYPE_TUN
- && info[0] == 9 && info[1] < 8)
+ /*
+ * If the TAP-Windows driver is masquerading as a DHCP server
+ * make sure the TCP/IP properties for the adapter are
+ * set correctly.
+ */
+ if (dhcp_masq_post)
+ {
+ /* check dhcp enable status */
+ if (dhcp_status(index) == DHCP_STATUS_DISABLED)
{
- msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will not work. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] );
+ msg(M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Windows TCP/IP properties are set to 'Obtain an IP address automatically'");
}
- /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy
- */
- if (tt->type == DEV_TYPE_TUN
- && info[0] == 9 && info[1] == 8)
+ /* force an explicit DHCP lease renewal on TAP adapter? */
+ if (tt->options.dhcp_pre_release)
{
- msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] );
+ dhcp_release(tt);
}
+ if (tt->options.dhcp_renew)
+ {
+ dhcp_renew(tt);
+ }
+ }
+ else
+ {
+ fork_dhcp_action(tt);
}
- /* get driver MTU */
+ if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI)
{
- ULONG mtu;
- if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_MTU,
- &mtu, sizeof(mtu),
- &mtu, sizeof(mtu), &len, NULL))
+ DWORD status;
+ const char *error_suffix = "I am having trouble using the Windows 'IP helper API' to automatically set the IP address -- consider using other --ip-win32 methods (not 'ipapi')";
+
+ /* couldn't get adapter index */
+ if (index == TUN_ADAPTER_INDEX_INVALID)
{
- tt->post_open_mtu = (int) mtu;
- msg(D_MTU_INFO, "TAP-Windows MTU=%d", (int) mtu);
+ msg(M_FATAL, "ERROR: unable to get adapter index for interface %s -- %s",
+ device_guid,
+ error_suffix);
}
- }
- /*
- * Preliminaries for setting TAP-Windows 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)
+ /* check dhcp enable status */
+ if (dhcp_status(index) == DHCP_STATUS_DISABLED)
{
- /*
- * If adapter is set to non-DHCP, set to DHCP mode.
- */
- if (dhcp_status(tt->adapter_index) == DHCP_STATUS_DISABLED)
- {
- /* try using the service if available, else directly execute netsh */
- if (tt->options.msg_channel)
- {
- service_enable_dhcp(tt);
- }
- else
- {
- netsh_enable_dhcp(tt->actual_name);
- }
- }
- dhcp_masq = true;
- dhcp_masq_post = true;
+ 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-Windows TCP/IP properties are set to 'Obtain an IP address automatically'");
}
- else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
+
+ /* delete previously added IP addresses which were not
+ * correctly deleted */
+ delete_temp_addresses(index);
+
+ /* add a new IP address */
+ if ((status = AddIPAddress(htonl(tt->local),
+ htonl(tt->adapter_netmask),
+ index,
+ &tt->ipapi_context,
+ &tt->ipapi_instance)) == NO_ERROR)
{
- /*
- * 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;
- }
+ msg(M_INFO, "Succeeded in adding a temporary IP/netmask of %s/%s to interface %s using the Win32 IP Helper API",
+ print_in_addr_t(tt->local, 0, &gc),
+ print_in_addr_t(tt->adapter_netmask, 0, &gc),
+ device_guid
+ );
+ }
+ else
+ {
+ msg(M_FATAL, "ERROR: AddIPAddress %s/%s failed on interface %s, index=%lu, status=%lu (windows error: '%s') -- %s",
+ print_in_addr_t(tt->local, 0, &gc),
+ print_in_addr_t(tt->adapter_netmask, 0, &gc),
+ device_guid,
+ index,
+ status,
+ strerror_win32(status, &gc),
+ error_suffix);
}
+ tt->ipapi_context_defined = true;
}
- /* set point-to-point mode if TUN device */
+ gc_free(&gc);
+}
- if (tt->type == DEV_TYPE_TUN)
+static bool
+wintun_register_ring_buffer(struct tuntap *tt, const char *device_guid)
+{
+ bool ret = true;
+
+ tt->wintun_send_ring = (struct tun_ring *)MapViewOfFile(tt->wintun_send_ring_handle,
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ sizeof(struct tun_ring));
+
+ tt->wintun_receive_ring = (struct tun_ring *)MapViewOfFile(tt->wintun_receive_ring_handle,
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ sizeof(struct tun_ring));
+
+ if (tt->options.msg_channel)
{
- if (!tt->did_ifconfig_setup)
- {
- msg(M_FATAL, "ERROR: --dev tun also requires --ifconfig");
- }
+ ret = service_register_ring_buffers(tt);
+ }
+ else
+ {
+ msg(M_FATAL, "ERROR: Wintun requires SYSTEM privileges and therefore "
+ "should be used with interactive service. If you want to "
+ "use openvpn from command line, you need to do SYSTEM "
+ "elevation yourself (for example with psexec).");
+ }
- if (tt->topology == TOP_SUBNET)
- {
- in_addr_t ep[3];
- BOOL status;
+ return ret;
+}
- ep[0] = htonl(tt->local);
- ep[1] = htonl(tt->local & tt->remote_netmask);
- ep[2] = htonl(tt->remote_netmask);
+static void
+tuntap_set_connected(const struct tuntap *tt)
+{
+ ULONG status = TRUE;
+ DWORD len;
+ if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
+ &status, sizeof(status),
+ &status, sizeof(status), &len, NULL))
+ {
+ msg(M_WARN, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
+ }
- status = DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_TUN,
- ep, sizeof(ep),
- ep, sizeof(ep), &len, NULL);
+ int s = tt->options.tap_sleep;
+ if (s > 0)
+ {
+ msg(M_INFO, "Sleeping for %d seconds...", s);
+ management_sleep(s);
+ }
+}
+static void
+tuntap_set_ptp(const struct tuntap *tt)
+{
+ DWORD len;
+ struct gc_arena gc = gc_new();
+
+ if (!tt->did_ifconfig_setup && !tt->did_ifconfig_ipv6_setup)
+ {
+ msg(M_FATAL, "ERROR: --dev tun also requires --ifconfig");
+ }
+
+ /* send 0/0/0 to the TAP driver even if we have no IPv4 configured to
+ * ensure it is somehow initialized.
+ */
+ if (!tt->did_ifconfig_setup || tt->topology == TOP_SUBNET)
+ {
+ in_addr_t ep[3];
+ BOOL status;
+
+ ep[0] = htonl(tt->local);
+ ep[1] = htonl(tt->local & tt->remote_netmask);
+ ep[2] = htonl(tt->remote_netmask);
+
+ status = DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_TUN,
+ ep, sizeof(ep),
+ ep, sizeof(ep), &len, NULL);
+
+ if (tt->did_ifconfig_setup)
+ {
msg(status ? M_INFO : M_FATAL, "Set TAP-Windows TUN subnet mode network/local/netmask = %s/%s/%s [%s]",
print_in_addr_t(ep[1], IA_NET_ORDER, &gc),
print_in_addr_t(ep[0], IA_NET_ORDER, &gc),
print_in_addr_t(ep[2], IA_NET_ORDER, &gc),
status ? "SUCCEEDED" : "FAILED");
-
}
else
{
+ msg(status ? M_INFO : M_FATAL, "Set TAP-Windows TUN with fake IPv4 [%s]",
+ status ? "SUCCEEDED" : "FAILED");
+ }
+ }
+ else
+ {
+ in_addr_t ep[2];
+ ep[0] = htonl(tt->local);
+ ep[1] = htonl(tt->remote_netmask);
- in_addr_t ep[2];
- ep[0] = htonl(tt->local);
- ep[1] = htonl(tt->remote_netmask);
-
- if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT,
- ep, sizeof(ep),
- ep, sizeof(ep), &len, NULL))
- {
- msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun");
- }
+ if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT,
+ ep, sizeof(ep),
+ ep, sizeof(ep), &len, NULL))
+ {
+ msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun");
}
}
- /* should we tell the TAP-Windows driver to masquerade as a DHCP server as a means
- * of setting the adapter address? */
- if (dhcp_masq)
- {
- uint32_t ep[4];
+ gc_free(&gc);
+}
- /* We will answer DHCP requests with a reply to set IP/subnet to these values */
- ep[0] = htonl(tt->local);
- ep[1] = htonl(tt->adapter_netmask);
+static void
+tuntap_dhcp_mask(const struct tuntap *tt, const char *device_guid)
+{
+ struct gc_arena gc = gc_new();
+ DWORD len;
+ uint32_t ep[4];
- /* At what IP address should the DHCP server masquerade at? */
- if (tt->type == DEV_TYPE_TUN)
+ /* We will answer DHCP requests with a reply to set IP/subnet to these values */
+ ep[0] = htonl(tt->local);
+ ep[1] = htonl(tt->adapter_netmask);
+
+ /* At what IP address should the DHCP server masquerade at? */
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ if (tt->topology == TOP_SUBNET)
{
- if (tt->topology == TOP_SUBNET)
+ if (tt->options.dhcp_masq_custom_offset)
{
- if (tt->options.dhcp_masq_custom_offset)
- {
- ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, tt->options.dhcp_masq_offset);
- }
- else
- {
- ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, -1);
- }
+ ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, tt->options.dhcp_masq_offset);
}
else
{
- ep[2] = htonl(tt->remote_netmask);
+ ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, -1);
}
}
else
{
- ASSERT(tt->type == DEV_TYPE_TAP);
- ep[2] = dhcp_masq_addr(tt->local, tt->adapter_netmask, tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0);
+ ep[2] = htonl(tt->remote_netmask);
}
+ }
+ else
+ {
+ ASSERT(tt->type == DEV_TYPE_TAP);
+ ep[2] = dhcp_masq_addr(tt->local, tt->adapter_netmask, tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0);
+ }
- /* lease time in seconds */
- ep[3] = (uint32_t) tt->options.dhcp_lease_time;
+ /* lease time in seconds */
+ ep[3] = (uint32_t)tt->options.dhcp_lease_time;
- ASSERT(ep[3] > 0);
+ ASSERT(ep[3] > 0);
#ifndef SIMULATE_DHCP_FAILED /* this code is disabled to simulate bad DHCP negotiation */
- if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_MASQ,
- ep, sizeof(ep),
- ep, sizeof(ep), &len, NULL))
- {
- msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode");
- }
+ if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_MASQ,
+ ep, sizeof(ep),
+ ep, sizeof(ep), &len, NULL))
+ {
+ msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode");
+ }
- msg(M_INFO, "Notified TAP-Windows driver to set a DHCP IP/netmask of %s/%s on interface %s [DHCP-serv: %s, lease-time: %d]",
- print_in_addr_t(tt->local, 0, &gc),
- print_in_addr_t(tt->adapter_netmask, 0, &gc),
- device_guid,
- print_in_addr_t(ep[2], IA_NET_ORDER, &gc),
- ep[3]
- );
+ msg(M_INFO, "Notified TAP-Windows driver to set a DHCP IP/netmask of %s/%s on interface %s [DHCP-serv: %s, lease-time: %d]",
+ print_in_addr_t(tt->local, 0, &gc),
+ print_in_addr_t(tt->adapter_netmask, 0, &gc),
+ device_guid,
+ print_in_addr_t(ep[2], IA_NET_ORDER, &gc),
+ ep[3]
+ );
- /* user-supplied DHCP options capability */
- if (tt->options.dhcp_options)
+ /* user-supplied DHCP options capability */
+ if (tt->options.dhcp_options)
+ {
+ struct buffer buf = alloc_buf(256);
+ if (build_dhcp_options_string(&buf, &tt->options))
{
- struct buffer buf = alloc_buf(256);
- if (build_dhcp_options_string(&buf, &tt->options))
+ msg(D_DHCP_OPT, "DHCP option string: %s", format_hex(BPTR(&buf), BLEN(&buf), 0, &gc));
+ if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT,
+ BPTR(&buf), BLEN(&buf),
+ BPTR(&buf), BLEN(&buf), &len, NULL))
{
- msg(D_DHCP_OPT, "DHCP option string: %s", format_hex(BPTR(&buf), BLEN(&buf), 0, &gc));
- if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT,
- BPTR(&buf), BLEN(&buf),
- BPTR(&buf), BLEN(&buf), &len, NULL))
- {
- msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call");
- }
- }
- else
- {
- msg(M_WARN, "DHCP option string not set due to error");
+ msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call");
}
- free_buf(&buf);
}
-#endif /* ifndef SIMULATE_DHCP_FAILED */
+ else
+ {
+ msg(M_WARN, "DHCP option string not set due to error");
+ }
+ free_buf(&buf);
}
+#endif /* ifndef SIMULATE_DHCP_FAILED */
- /* set driver media status to 'connected' */
+ gc_free(&gc);
+}
+
+static bool
+tun_try_open_device(struct tuntap *tt, const char *device_guid, const struct device_instance_id_interface *device_instance_id_interface)
+{
+ const char *path = NULL;
+ char tuntap_device_path[256];
+
+ if (tt->windows_driver == WINDOWS_DRIVER_WINTUN)
{
- ULONG status = TRUE;
- if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
- &status, sizeof(status),
- &status, sizeof(status), &len, NULL))
+ const struct device_instance_id_interface *dev_if;
+
+ /* Open Wintun adapter */
+ for (dev_if = device_instance_id_interface; dev_if != NULL; dev_if = dev_if->next)
{
- msg(M_WARN, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
+ if (strcmp(dev_if->net_cfg_instance_id, device_guid) == 0)
+ {
+ path = dev_if->device_interface_list;
+ break;
+ }
}
+ if (path == NULL)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ /* Open TAP-Windows adapter */
+ openvpn_snprintf(tuntap_device_path, sizeof(tuntap_device_path), "%s%s%s",
+ USERMODEDEVICEDIR,
+ device_guid,
+ TAP_WIN_SUFFIX);
+ path = tuntap_device_path;
}
- /* possible wait for adapter to come up */
+ tt->hand = CreateFile(path,
+ GENERIC_READ | GENERIC_WRITE,
+ 0, /* was: FILE_SHARE_READ */
+ 0,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
+ 0);
+ if (tt->hand == INVALID_HANDLE_VALUE)
{
- int s = tt->options.tap_sleep;
- if (s > 0)
+ msg(D_TUNTAP_INFO, "CreateFile failed on %s device: %s", print_windows_driver(tt->windows_driver), path);
+ return false;
+ }
+
+ if (tt->windows_driver == WINDOWS_DRIVER_WINTUN)
+ {
+ /* Wintun adapter may be considered "open" after ring buffers are successfuly registered. */
+ if (!wintun_register_ring_buffer(tt, device_guid))
{
- msg(M_INFO, "Sleeping for %d seconds...", s);
- management_sleep(s);
+ msg(D_TUNTAP_INFO, "Failed to register %s adapter ring buffers", device_guid);
+ CloseHandle(tt->hand);
+ tt->hand = NULL;
+ return false;
}
}
- /* possibly use IP Helper API to set IP address on adapter */
+ return true;
+}
+
+static void
+tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid, struct gc_arena *gc)
+{
+ const struct tap_reg *tap_reg = get_tap_reg(gc);
+ const struct panel_reg *panel_reg = get_panel_reg(gc);
+ const struct device_instance_id_interface *device_instance_id_interface = get_device_instance_id_interface(gc);
+ char actual_buffer[256];
+
+ at_least_one_tap_win(tap_reg);
+
+ /*
+ * Lookup the device name in the registry, using the --dev-node high level name.
+ */
+ if (dev_node)
{
- const DWORD index = tt->adapter_index;
+ enum windows_driver_type windows_driver = WINDOWS_DRIVER_UNSPECIFIED;
+
+ /* Get the device GUID for the device specified with --dev-node. */
+ *device_guid = get_device_guid(dev_node, actual_buffer, sizeof(actual_buffer), &windows_driver, tap_reg, panel_reg, gc);
- /* flush arp cache */
- if (index != TUN_ADAPTER_INDEX_INVALID)
+ if (!*device_guid)
{
- DWORD status = -1;
+ msg(M_FATAL, "Adapter '%s' not found", dev_node);
+ }
- if (tt->options.msg_channel)
- {
- ack_message_t ack;
- flush_neighbors_message_t msg = {
- .header = {
- msg_flush_neighbors,
- sizeof(flush_neighbors_message_t),
- 0
- },
- .family = AF_INET,
- .iface = { .index = index, .name = "" }
- };
-
- if (!WriteFile(tt->options.msg_channel, &msg, sizeof(msg), &len, NULL)
- || !ReadFile(tt->options.msg_channel, &ack, sizeof(ack), &len, NULL))
- {
- msg(M_WARN, "TUN: could not talk to service: %s [%lu]",
- strerror_win32(GetLastError(), &gc), GetLastError());
- }
+ if (tt->windows_driver != windows_driver)
+ {
+ msg(M_FATAL, "Adapter '%s' is using %s driver, %s expected. If you want to use this device, adjust --windows-driver.",
+ dev_node, print_windows_driver(windows_driver), print_windows_driver(tt->windows_driver));
+ }
- status = ack.error_number;
- }
- else
+ if (!tun_try_open_device(tt, *device_guid, device_instance_id_interface))
+ {
+ msg(M_FATAL, "Failed to open %s adapter: %s", print_windows_driver(tt->windows_driver), dev_node);
+ }
+ }
+ else
+ {
+ int device_number = 0;
+
+ /* Try opening all TAP devices until we find one available */
+ while (true)
+ {
+ enum windows_driver_type windows_driver = WINDOWS_DRIVER_UNSPECIFIED;
+ *device_guid = get_unspecified_device_guid(device_number,
+ actual_buffer,
+ sizeof(actual_buffer),
+ tap_reg,
+ panel_reg,
+ &windows_driver,
+ gc);
+
+ if (!*device_guid)
{
- status = FlushIpNetTable(index);
+ msg(M_FATAL, "All %s adapters on this system are currently in use.", print_windows_driver(tt->windows_driver));
}
- if (status == NO_ERROR)
+ if (tt->windows_driver != windows_driver)
{
- msg(M_INFO, "Successful ARP Flush on interface [%u] %s",
- (unsigned int)index,
- device_guid);
+ goto next;
}
- else if (status != -1)
+
+ if (tun_try_open_device(tt, *device_guid, device_instance_id_interface))
{
- msg(D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s",
- (unsigned int)index,
- device_guid,
- (unsigned int)status,
- strerror_win32(status, &gc));
+ break;
}
+
+next:
+ device_number++;
}
+ }
+
+ /* translate high-level device name into a device instance
+ * GUID using the registry */
+ tt->actual_name = string_alloc(actual_buffer, NULL);
+ msg(M_INFO, "%s device [%s] opened", print_windows_driver(tt->windows_driver), tt->actual_name);
+ tt->adapter_index = get_adapter_index(*device_guid);
+}
+
+static void
+tuntap_set_ip_props(const struct tuntap *tt, bool *dhcp_masq, bool *dhcp_masq_post)
+{
+ if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ)
+ {
/*
- * If the TAP-Windows driver is masquerading as a DHCP server
- * make sure the TCP/IP properties for the adapter are
- * set correctly.
+ * If adapter is set to non-DHCP, set to DHCP mode.
*/
- if (dhcp_masq_post)
+ if (dhcp_status(tt->adapter_index) == DHCP_STATUS_DISABLED)
{
- /* check dhcp enable status */
- if (dhcp_status(index) == DHCP_STATUS_DISABLED)
- {
- msg(M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Windows TCP/IP properties are set to 'Obtain an IP address automatically'");
- }
-
- /* force an explicit DHCP lease renewal on TAP adapter? */
- if (tt->options.dhcp_pre_release)
+ /* try using the service if available, else directly execute netsh */
+ if (tt->options.msg_channel)
{
- dhcp_release(tt);
+ service_enable_dhcp(tt);
}
- if (tt->options.dhcp_renew)
+ else
{
- dhcp_renew(tt);
+ netsh_enable_dhcp(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
{
- fork_dhcp_action(tt);
+ *dhcp_masq = true;
}
+ }
+}
- if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI)
- {
- DWORD status;
- const char *error_suffix = "I am having trouble using the Windows 'IP helper API' to automatically set the IP address -- consider using other --ip-win32 methods (not 'ipapi')";
+static void
+tuntap_post_open(struct tuntap *tt, const char *device_guid)
+{
+ bool dhcp_masq = false;
+ bool dhcp_masq_post = false;
- /* couldn't get adapter index */
- if (index == TUN_ADAPTER_INDEX_INVALID)
- {
- msg(M_FATAL, "ERROR: unable to get adapter index for interface %s -- %s",
- device_guid,
- error_suffix);
- }
+ if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6)
+ {
+ /* get driver version info */
+ tuntap_get_version_info(tt);
- /* check dhcp enable status */
- 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-Windows TCP/IP properties are set to 'Obtain an IP address automatically'");
- }
+ /* get driver MTU */
+ tuntap_get_mtu(tt);
- /* delete previously added IP addresses which were not
- * correctly deleted */
- delete_temp_addresses(index);
+ /*
+ * Preliminaries for setting TAP-Windows adapter TCP/IP
+ * properties via --ip-win32 dynamic or --ip-win32 adaptive.
+ */
+ if (tt->did_ifconfig_setup)
+ {
+ tuntap_set_ip_props(tt, &dhcp_masq, &dhcp_masq_post);
+ }
- /* add a new IP address */
- if ((status = AddIPAddress(htonl(tt->local),
- htonl(tt->adapter_netmask),
- index,
- &tt->ipapi_context,
- &tt->ipapi_instance)) == NO_ERROR)
- {
- msg(M_INFO, "Succeeded in adding a temporary IP/netmask of %s/%s to interface %s using the Win32 IP Helper API",
- print_in_addr_t(tt->local, 0, &gc),
- print_in_addr_t(tt->adapter_netmask, 0, &gc),
- device_guid
- );
- }
- else
- {
- msg(M_FATAL, "ERROR: AddIPAddress %s/%s failed on interface %s, index=%d, status=%u (windows error: '%s') -- %s",
- print_in_addr_t(tt->local, 0, &gc),
- print_in_addr_t(tt->adapter_netmask, 0, &gc),
- device_guid,
- (int)index,
- (unsigned int)status,
- strerror_win32(status, &gc),
- error_suffix);
- }
- tt->ipapi_context_defined = true;
+ /* set point-to-point mode if TUN device */
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ tuntap_set_ptp(tt);
}
+
+ /* should we tell the TAP-Windows driver to masquerade as a DHCP server as a means
+ * of setting the adapter address? */
+ if (dhcp_masq)
+ {
+ tuntap_dhcp_mask(tt, device_guid);
+ }
+
+ /* set driver media status to 'connected' */
+ tuntap_set_connected(tt);
}
- /*netcmd_semaphore_release ();*/
+
+ /* possibly use IP Helper API to set IP address on adapter */
+ tuntap_set_ip_addr(tt, device_guid, dhcp_masq_post);
+}
+
+void
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ const char *device_guid = NULL;
+
+ /*netcmd_semaphore_lock ();*/
+
+ msg( M_INFO, "open_tun");
+
+ if (tt->type == DEV_TYPE_NULL)
+ {
+ open_null(tt);
+ return;
+ }
+ else if (tt->type != DEV_TYPE_TAP && tt->type != DEV_TYPE_TUN)
+ {
+ msg(M_FATAL|M_NOPREFIX, "Unknown virtual device type: '%s'", dev);
+ }
+
+ struct gc_arena gc = gc_new(); /* used also for device_guid allocation */
+ tun_open_device(tt, dev_node, &device_guid, &gc);
+
+ tuntap_post_open(tt, device_guid);
+
gc_free(&gc);
+
+ /*netcmd_semaphore_release ();*/
}
const char *
tap_win_getinfo(const struct tuntap *tt, struct gc_arena *gc)
{
- if (tt && tt->hand != NULL)
+ if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6)
{
struct buffer out = alloc_buf_gc(256, gc);
DWORD len;
@@ -6226,7 +6606,7 @@ tap_win_getinfo(const struct tuntap *tt, struct gc_arena *gc)
void
tun_show_debug(struct tuntap *tt)
{
- if (tt && tt->hand != NULL)
+ if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6)
{
struct buffer out = alloc_buf(1024);
DWORD len;
@@ -6241,107 +6621,160 @@ tun_show_debug(struct tuntap *tt)
}
}
-void
-close_tun(struct tuntap *tt)
+static void
+netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc)
{
- struct gc_arena gc = gc_new();
+ const char *ifconfig_ip_local;
+ struct argv argv = argv_new();
- if (tt)
+ /* delete ipvX dns servers if any were set */
+ int len = ipv6 ? tt->options.dns6_len : tt->options.dns_len;
+ if (len > 0)
{
- if (tt->did_ifconfig_ipv6_setup)
- {
- /* remove route pointing to interface */
- delete_route_connected_v6_net(tt, NULL);
+ argv_printf(&argv,
+ "%s%s interface %s delete dns %s all",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ ipv6 ? "ipv6" : "ipv4",
+ tt->actual_name);
+ netsh_command(&argv, 1, M_WARN);
+ }
- if (tt->options.msg_channel)
- {
- do_address_service(false, AF_INET6, tt);
- if (tt->options.dns6_len > 0)
- {
- do_dns6_service(false, tt);
- }
- }
- else
- {
- const char *ifconfig_ipv6_local;
- struct argv argv = argv_new();
+ if (ipv6)
+ {
+ delete_route_connected_v6_net(tt);
+ }
- /* "store=active" is needed in Windows 8(.1) to delete the
- * address we added (pointed out by Cedric Tabary).
- */
+ /* "store=active" is needed in Windows 8(.1) to delete the
+ * address we added (pointed out by Cedric Tabary).
+ */
- /* netsh interface ipv6 delete address \"%s\" %s */
- ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc);
- argv_printf(&argv,
- "%s%sc interface ipv6 delete address %s %s store=active",
- get_win_sys_path(),
- NETSH_PATH_SUFFIX,
- tt->actual_name,
- ifconfig_ipv6_local);
+ /* netsh interface ipvX delete address \"%s\" %s */
+ if (ipv6)
+ {
+ ifconfig_ip_local = print_in6_addr(tt->local_ipv6, 0, gc);
+ }
+ else
+ {
+ ifconfig_ip_local = print_in_addr_t(tt->local, 0, gc);
+ }
+ argv_printf(&argv,
+ "%s%s interface %s delete address %s %s store=active",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ ipv6 ? "ipv6" : "ipv4",
+ tt->actual_name,
+ ifconfig_ip_local);
+ netsh_command(&argv, 1, M_WARN);
- netsh_command(&argv, 1, M_WARN);
+ argv_free(&argv);
+}
- /* 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);
- }
+void
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
+{
+ ASSERT(tt);
+
+ struct gc_arena gc = gc_new();
+
+ if (tt->did_ifconfig_ipv6_setup)
+ {
+ if (tt->options.ip_win32_type == IPW32_SET_MANUAL)
+ {
+ /* We didn't do ifconfig. */
}
-#if 1
- if (tt->ipapi_context_defined)
+ else if (tt->options.msg_channel)
{
- DWORD status;
- if ((status = DeleteIPAddress(tt->ipapi_context)) != NO_ERROR)
+ if (tt->options.dns6_len > 0)
{
- msg(M_WARN, "Warning: DeleteIPAddress[%u] failed on TAP-Windows adapter, status=%u : %s",
- (unsigned int)tt->ipapi_context,
- (unsigned int)status,
- strerror_win32(status, &gc));
+ do_dns_service(false, AF_INET6, tt);
}
+ delete_route_connected_v6_net(tt);
+ do_address_service(false, AF_INET6, tt);
}
-#endif
-
- dhcp_release(tt);
+ else
+ {
+ netsh_delete_address_dns(tt, true, &gc);
+ }
+ }
- if (tt->hand != NULL)
+ if (tt->did_ifconfig_setup)
+ {
+ if (tt->options.ip_win32_type == IPW32_SET_MANUAL)
{
- dmsg(D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Windows adapter");
- if (!CancelIo(tt->hand))
- {
- msg(M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Windows adapter");
- }
+ /* We didn't do ifconfig. */
}
+ else if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ || tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
+ {
+ /* We don't have to clean the configuration with DHCP. */
+ }
+ else if (tt->options.msg_channel)
+ {
+ do_dns_service(false, AF_INET, tt);
+ do_address_service(false, AF_INET, tt);
+ }
+ else if (tt->options.ip_win32_type == IPW32_SET_NETSH)
+ {
+ netsh_delete_address_dns(tt, false, &gc);
+ }
+ }
- dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Windows adapter");
- overlapped_io_close(&tt->reads);
+ if (tt->ipapi_context_defined)
+ {
+ DWORD status;
+ if ((status = DeleteIPAddress(tt->ipapi_context)) != NO_ERROR)
+ {
+ msg(M_WARN, "Warning: DeleteIPAddress[%u] failed on TAP-Windows adapter, status=%u : %s",
+ (unsigned int)tt->ipapi_context,
+ (unsigned int)status,
+ strerror_win32(status, &gc));
+ }
+ }
- dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Windows adapter");
- overlapped_io_close(&tt->writes);
+ dhcp_release(tt);
- if (tt->hand != NULL)
+ if (tt->hand != NULL)
+ {
+ dmsg(D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Windows adapter");
+ if (!CancelIo(tt->hand))
{
- dmsg(D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Windows adapter");
- if (!CloseHandle(tt->hand))
- {
- msg(M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Windows adapter");
- }
+ msg(M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Windows adapter");
}
+ }
- if (tt->actual_name)
+ dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Windows adapter");
+ overlapped_io_close(&tt->reads);
+
+ dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Windows adapter");
+ overlapped_io_close(&tt->writes);
+
+ if (tt->hand != NULL)
+ {
+ dmsg(D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Windows adapter");
+ if (!CloseHandle(tt->hand))
{
- free(tt->actual_name);
+ msg(M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Windows adapter");
}
+ }
- clear_tuntap(tt);
- free(tt);
+ if (tt->actual_name)
+ {
+ free(tt->actual_name);
+ }
+
+ if (tt->windows_driver == WINDOWS_DRIVER_WINTUN)
+ {
+ CloseHandle(tt->rw_handle.read);
+ CloseHandle(tt->rw_handle.write);
+ UnmapViewOfFile(tt->wintun_send_ring);
+ UnmapViewOfFile(tt->wintun_receive_ring);
+ CloseHandle(tt->wintun_send_ring_handle);
+ CloseHandle(tt->wintun_receive_ring_handle);
}
+
+
+ clear_tuntap(tt);
+ free(tt);
gc_free(&gc);
}
@@ -6418,13 +6851,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
}
void
-close_tun(struct tuntap *tt)
+close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx)
{
- if (tt)
- {
- close_tun_generic(tt);
- free(tt);
- }
+ ASSERT(tt);
+
+ close_tun_generic(tt);
+ free(tt);
}
int