diff options
author | Christian Pointner <equinox@anytun.org> | 2008-05-20 14:36:04 +0000 |
---|---|---|
committer | Christian Pointner <equinox@anytun.org> | 2008-05-20 14:36:04 +0000 |
commit | b2f54ec4947b60b9d989cb887f6c62c93a738e02 (patch) | |
tree | d32b3f7427c836adfaea53e0a16fd43585e79879 /src/openvpn/tun.c | |
parent | added -i option to anyrtpproxy (diff) |
removed openvpn source code
Diffstat (limited to 'src/openvpn/tun.c')
-rw-r--r-- | src/openvpn/tun.c | 3446 |
1 files changed, 0 insertions, 3446 deletions
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c deleted file mode 100644 index e904a0c..0000000 --- a/src/openvpn/tun.c +++ /dev/null @@ -1,3446 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single TCP/UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Support routines for configuring and accessing TUN/TAP - * virtual network adapters. - * - * This file is based on the TUN/TAP driver interface routines - * from VTun by Maxim Krasnyansky <max_mk@yahoo.com>. - */ - -#ifdef WIN32 -#include "config-win32.h" -#else -#include "config.h" -#endif - -#include "syshead.h" - -#include "tun.h" -#include "fdmisc.h" -#include "common.h" -#include "misc.h" -#include "socket.h" -#include "manage.h" - -#include "memdbg.h" - -#ifdef TARGET_SOLARIS -static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual); -#endif - -bool -is_dev_type (const char *dev, const char *dev_type, const char *match_type) -{ - ASSERT (match_type); - if (!dev) - return false; - if (dev_type) - return !strcmp (dev_type, match_type); - else - return !strncmp (dev, match_type, strlen (match_type)); -} - -int -dev_type_enum (const char *dev, const char *dev_type) -{ - if (is_dev_type (dev, dev_type, "tun")) - return DEV_TYPE_TUN; - else if (is_dev_type (dev, dev_type, "tap")) - return DEV_TYPE_TAP; - else if (is_dev_type (dev, dev_type, "null")) - return DEV_TYPE_NULL; - else - return DEV_TYPE_UNDEF; -} - -const char * -dev_type_string (const char *dev, const char *dev_type) -{ - switch (dev_type_enum (dev, dev_type)) - { - case DEV_TYPE_TUN: - return "tun"; - case DEV_TYPE_TAP: - return "tap"; - case DEV_TYPE_NULL: - return "null"; - default: - return "[unknown-dev-type]"; - } -} - -const char * -dev_component_in_dev_node (const char *dev_node) -{ - const char *ret; - const int dirsep = OS_SPECIFIC_DIRSEP; - - if (dev_node) - { - ret = strrchr (dev_node, dirsep); - if (ret && *ret) - ++ret; - else - ret = dev_node; - if (*ret) - return ret; - } - return NULL; -} - -/* - * Try to predict the actual TUN/TAP device instance name, - * before the device is actually opened. - */ -const char * -guess_tuntap_dev (const char *dev, - const char *dev_type, - const char *dev_node, - struct gc_arena *gc) -{ -#ifdef WIN32 - const int dt = dev_type_enum (dev, dev_type); - if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP) - { - return get_netsh_id (dev_node, gc); - } -#endif - - /* default case */ - return dev; -} - -/* - * Called by the open_tun function of OSes to check if we - * explicitly support IPv6. - * - * In this context, explicit means that the OS expects us to - * do something special to the tun socket in order to support - * IPv6, i.e. it is not transparent. - * - * ipv6_explicitly_supported should be set to false if we don't - * have any explicit IPv6 code in the tun device handler. - * - * If ipv6_explicitly_supported is true, then we have explicit - * OS-specific tun dev code for handling IPv6. If so, tt->ipv6 - * is set according to the --tun-ipv6 command line option. - */ -static void -ipv6_support (bool ipv6, bool ipv6_explicitly_supported, struct tuntap* tt) -{ - tt->ipv6 = false; - if (ipv6_explicitly_supported) - tt->ipv6 = ipv6; - else if (ipv6) - msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); -} - -/* --ifconfig-nowarn disables some options sanity checking */ -static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)"; - -/* - * If !tun, make sure ifconfig_remote_netmask looks - * like a netmask. - * - * If tun, make sure ifconfig_remote_netmask looks - * like an IPv4 address. - */ -static void -ifconfig_sanity_check (bool tun, in_addr_t addr) -{ - struct gc_arena gc = gc_new (); - const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000); - if (tun) - { - if (looks_like_netmask) - msg (M_WARN, "WARNING: Since you are using --dev tun, the second argument to --ifconfig must be an IP address. You are using something (%s) that looks more like a netmask. %s", - print_in_addr_t (addr, 0, &gc), - ifconfig_warn_how_to_silence); - } - else /* tap */ - { - if (!looks_like_netmask) - msg (M_WARN, "WARNING: Since you are using --dev tap, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s", - ifconfig_warn_how_to_silence); - } - gc_free (&gc); -} - -/* - * 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. - */ -static void -check_addr_clash (const char *name, - int type, - in_addr_t public, - in_addr_t local, - in_addr_t remote_netmask) -{ - struct gc_arena gc = gc_new (); -#if 0 - msg (M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s", - type, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc)); -#endif - - if (public) - { - if (type == DEV_TYPE_TUN) - { - const in_addr_t test_netmask = 0xFFFFFF00; - const in_addr_t public_net = public & test_netmask; - const in_addr_t local_net = local & test_netmask; - const in_addr_t remote_net = remote_netmask & test_netmask; - - if (public == local || public == remote_netmask) - msg (M_WARN, - "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s", - name, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc), - ifconfig_warn_how_to_silence); - - if (public_net == local_net || public_net == remote_net) - msg (M_WARN, - "WARNING: potential conflict between --%s address [%s] and --ifconfig address pair [%s, %s] -- this is a warning only that is triggered when local/remote addresses exist within the same /24 subnet as --ifconfig endpoints. %s", - name, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc), - ifconfig_warn_how_to_silence); - } - else if (type == DEV_TYPE_TAP) - { - const in_addr_t public_network = public & remote_netmask; - const in_addr_t virtual_network = local & remote_netmask; - if (public_network == virtual_network) - msg (M_WARN, - "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s", - name, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc), - ifconfig_warn_how_to_silence); - } - } - gc_free (&gc); -} - -/* - * Complain if --dev tap and --ifconfig is used on an OS for which - * we don't have a custom tap ifconfig template below. - */ -static void -no_tap_ifconfig () -{ - msg (M_FATAL, "Sorry but you cannot use --dev tap and --ifconfig together on this OS because I have not yet been programmed to understand the appropriate ifconfig syntax to use for TAP-style devices on this OS. Your best alternative is to use an --up script and do the ifconfig command manually."); -} - -/* - * Return a string to be used for options compatibility check - * between peers. - */ -const char * -ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (256, gc); - if (tt->did_ifconfig_setup && !disable) - { - if (tt->type == DEV_TYPE_TUN) - { - const char *l, *r; - if (remote) - { - r = print_in_addr_t (tt->local, 0, gc); - l = print_in_addr_t (tt->remote_netmask, 0, gc); - } - else - { - l = print_in_addr_t (tt->local, 0, gc); - r = print_in_addr_t (tt->remote_netmask, 0, gc); - } - buf_printf (&out, "%s %s", r, l); - } - else if (tt->type == DEV_TYPE_TAP) - { - buf_printf (&out, "%s %s", - print_in_addr_t (tt->local & tt->remote_netmask, 0, gc), - print_in_addr_t (tt->remote_netmask, 0, gc)); - } - else - buf_printf (&out, "[undef]"); - } - return BSTR (&out); -} - -/* - * Return a status string describing wait state. - */ -const char * -tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (64, gc); - if (tt) - { - if (rwflags & EVENT_READ) - { - buf_printf (&out, "T%s", - (tt->rwflags_debug & EVENT_READ) ? "R" : "r"); -#ifdef WIN32 - buf_printf (&out, "%s", - overlapped_io_state_ascii (&tt->reads)); -#endif - } - if (rwflags & EVENT_WRITE) - { - buf_printf (&out, "T%s", - (tt->rwflags_debug & EVENT_WRITE) ? "W" : "w"); -#ifdef WIN32 - buf_printf (&out, "%s", - overlapped_io_state_ascii (&tt->writes)); -#endif - } - } - else - { - buf_printf (&out, "T?"); - } - return BSTR (&out); -} - -/* - * Init tun/tap object. - * - * Set up tuntap structure for ifconfig, - * but don't execute yet. - */ -struct tuntap * -init_tun (const char *dev, /* --dev option */ - const char *dev_type, /* --dev-type option */ - const char *ifconfig_local_parm, /* --ifconfig parm 1 */ - const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ - in_addr_t local_public, - in_addr_t remote_public, - const bool strict_warn, - struct env_set *es) -{ - struct gc_arena gc = gc_new (); - struct tuntap *tt; - - ALLOC_OBJ (tt, struct tuntap); - clear_tuntap (tt); - - tt->type = dev_type_enum (dev, dev_type); - - if (ifconfig_local_parm && ifconfig_remote_netmask_parm) - { - bool tun = false; - const char *ifconfig_local = NULL; - const char *ifconfig_remote_netmask = NULL; - const char *ifconfig_broadcast = NULL; - - /* - * We only handle TUN/TAP devices here, not --dev null devices. - */ - if (tt->type == DEV_TYPE_TUN) - tun = true; - else if (tt->type == DEV_TYPE_TAP) - tun = false; - else - msg (M_FATAL, "'%s' is not a TUN/TAP device. The --ifconfig option works only for TUN/TAP devices.", dev); - - /* - * Convert arguments to binary IPv4 addresses. - */ - - tt->local = getaddr ( - GETADDR_RESOLVE - | GETADDR_HOST_ORDER - | GETADDR_FATAL_ON_SIGNAL - | GETADDR_FATAL, - ifconfig_local_parm, - 0, - NULL, - NULL); - - tt->remote_netmask = getaddr ( - (tun ? GETADDR_RESOLVE : 0) - | GETADDR_HOST_ORDER - | GETADDR_FATAL_ON_SIGNAL - | GETADDR_FATAL, - ifconfig_remote_netmask_parm, - 0, - NULL, - NULL); - - /* - * Look for common errors in --ifconfig parms - */ - if (strict_warn) - { - ifconfig_sanity_check (tun, tt->remote_netmask); - - /* - * If local_public or remote_public addresses are defined, - * make sure they do not clash with our virtual subnet. - */ - - check_addr_clash ("local", - tt->type, - local_public, - tt->local, - tt->remote_netmask); - - check_addr_clash ("remote", - tt->type, - remote_public, - tt->local, - tt->remote_netmask); - } - - /* - * 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); - - /* - * If TAP-style interface, generate broadcast address. - */ - if (!tun) - { - tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask); - ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); - } - - /* - * Set environmental variables with ifconfig parameters. - */ - if (es) - { - setenv_str (es, "ifconfig_local", ifconfig_local); - if (tun) - { - setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask); - } - else - { - setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask); - setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast); - } - } - - tt->did_ifconfig_setup = true; - } - gc_free (&gc); - return tt; -} - -/* - * Platform specific tun initializations - */ -void -init_tun_post (struct tuntap *tt, - const struct frame *frame, - const struct tuntap_options *options) -{ - tt->options = *options; -#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 = ~0; -#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) -{ - struct gc_arena gc = gc_new (); - - if (tt->did_ifconfig_setup) - { - bool tun = false; - const char *ifconfig_local = NULL; - const char *ifconfig_remote_netmask = NULL; - const char *ifconfig_broadcast = NULL; - char command_line[256]; - - /* - * We only handle TUN/TAP devices here, not --dev null devices. - */ - if (tt->type == DEV_TYPE_TUN) - tun = true; - else if (tt->type == DEV_TYPE_TAP) - tun = false; - else - ASSERT (0); /* should have been caught in init_tun */ - - /* - * 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); - - /* - * If TAP-style device, generate broadcast address. - */ - if (!tun) - ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); - -#ifdef ENABLE_MANAGEMENT - if (management) - { - management_set_state (management, - OPENVPN_STATE_ASSIGN_IP, - NULL, - tt->local); - } -#endif - - -#if defined(TARGET_LINUX) -#ifdef CONFIG_FEATURE_IPROUTE - /* - * Set the MTU for the device - */ - openvpn_snprintf (command_line, sizeof (command_line), - IPROUTE_PATH " link set dev %s up mtu %d", - actual, - tun_mtu - ); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "Linux ip link set failed"); - - if (tun) { - - /* - * Set the address for the device - */ - openvpn_snprintf (command_line, sizeof (command_line), - IPROUTE_PATH " addr add dev %s local %s peer %s", - actual, - ifconfig_local, - ifconfig_remote_netmask - ); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "Linux ip addr add failed"); - } else { - openvpn_snprintf (command_line, sizeof (command_line), - IPROUTE_PATH " addr add dev %s %s/%d broadcast %s", - actual, - ifconfig_local, - count_netmask_bits(ifconfig_remote_netmask), - ifconfig_broadcast - ); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "Linux ip addr add failed"); - } - tt->did_ifconfig = true; -#else - if (tun) - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s pointopoint %s mtu %d", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu, - ifconfig_broadcast - ); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "Linux ifconfig failed"); - tt->did_ifconfig = true; - -#endif /*CONFIG_FEATURE_IPROUTE*/ -#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) - { - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s %s mtu %d up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - - msg (M_INFO, "%s", command_line); - if (!system_check (command_line, es, 0, "Solaris ifconfig phase-1 failed")) - solaris_error_close (tt, es, actual); - - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s netmask 255.255.255.255", - actual - ); - } - else - no_tap_ifconfig (); - - msg (M_INFO, "%s", command_line); - if (!system_check (command_line, es, 0, "Solaris ifconfig phase-2 failed")) - solaris_error_close (tt, es, actual); - - tt->did_ifconfig = true; - -#elif defined(TARGET_OPENBSD) - - /* - * OpenBSD tun devices appear to be persistent by default. It seems in order - * to make this work correctly, we need to delete the previous instance - * (if it exists), and re-ifconfig. Let me know if you know a better way. - */ - - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s destroy", - actual); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, 0, NULL); - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s create", - actual); - msg (M_INFO, "%s", command_line); - system_check (command_line, 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) - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s link0", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu, - ifconfig_broadcast - ); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "OpenBSD ifconfig failed"); - tt->did_ifconfig = true; - -#elif defined(TARGET_NETBSD) - - if (tun) - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - 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 - */ - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s netmask %s mtu %d broadcast %s", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu, - ifconfig_broadcast - ); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "NetBSD ifconfig failed"); - tt->did_ifconfig = true; - -#elif defined(TARGET_DARWIN) - - /* - * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD... - */ - - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s delete", - actual); - msg (M_INFO, "%s", command_line); - system_check (command_line, 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) - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s netmask %s mtu %d up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "Mac OS X ifconfig failed"); - tt->did_ifconfig = true; - -#elif defined(TARGET_FREEBSD) - - /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ - if (tun) - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s %s mtu %d netmask 255.255.255.255 up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s %s netmask %s mtu %d up", - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "FreeBSD ifconfig failed"); - tt->did_ifconfig = true; - -#elif defined (WIN32) - { - const char *netmask; - - /* - * Make sure that both ifconfig addresses are part of the - * same .252 subnet. - */ - if (tun) - { - verify_255_255_255_252 (tt->local, tt->remote_netmask); - tt->adapter_netmask = ~3; - netmask = print_in_addr_t (tt->adapter_netmask, 0, &gc); - } - else - { - netmask = ifconfig_remote_netmask; - tt->adapter_netmask = tt->remote_netmask; - } - - /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ - openvpn_snprintf (command_line, sizeof (command_line), - "netsh interface ip set address \"%s\" static %s %s", - actual, - ifconfig_local, - netmask); - - switch (tt->options.ip_win32_type) - { - case IPW32_SET_MANUAL: - msg (M_INFO, "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)", - actual, - ifconfig_local, - netmask); - break; - case IPW32_SET_NETSH: - if (!strcmp (actual, "NULL")) - msg (M_FATAL, "Error: When using --ip-win32 netsh, if you have more than one TAP-Win32 adapter, you must also specify --dev-node"); - netcmd_semaphore_lock (); - msg (M_INFO, "%s", command_line); - system_check (command_line, es, S_FATAL, "ERROR: netsh command failed"); - netcmd_semaphore_release (); - break; - } - tt->did_ifconfig = true; - } - -#else - msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); -#endif - } - gc_free (&gc); -} - -void -clear_tuntap (struct tuntap *tuntap) -{ - CLEAR (*tuntap); -#ifdef WIN32 - tuntap->hand = NULL; -#else - tuntap->fd = -1; -#endif -#ifdef TARGET_SOLARIS - tuntap->ip_fd = -1; -#endif - tuntap->ipv6 = false; -} - -static void -open_null (struct tuntap *tt) -{ - tt->actual_name = string_alloc ("null", NULL); -} - -#ifndef WIN32 -static void -open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, - bool ipv6, bool ipv6_explicitly_supported, bool dynamic, - struct tuntap *tt) -{ - char tunname[256]; - char dynamic_name[256]; - bool dynamic_opened = false; - - ipv6_support (ipv6, ipv6_explicitly_supported, tt); - - if (tt->type == DEV_TYPE_NULL) - { - open_null (tt); - } - else - { - /* - * --dev-node specified, so open an explicit device node - */ - if (dev_node) - { - openvpn_snprintf (tunname, sizeof (tunname), "%s", dev_node); - } - else - { - /* - * dynamic open is indicated by --dev specified without - * explicit unit number. Try opening /dev/[dev]n - * where n = [0, 255]. - */ - if (dynamic && !has_digit(dev)) - { - int i; - for (i = 0; i < 256; ++i) - { - openvpn_snprintf (tunname, sizeof (tunname), - "/dev/%s%d", dev, i); - openvpn_snprintf (dynamic_name, sizeof (dynamic_name), - "%s%d", dev, i); - if ((tt->fd = open (tunname, O_RDWR)) > 0) - { - dynamic_opened = true; - break; - } - msg (D_READ_WRITE | M_ERRNO, "Tried opening %s (failed)", tunname); - } - if (!dynamic_opened) - msg (M_FATAL, "Cannot allocate TUN/TAP dev dynamically"); - } - /* - * explicit unit number specified - */ - else - { - openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev); - } - } - - if (!dynamic_opened) - { - if ((tt->fd = open (tunname, O_RDWR)) < 0) - msg (M_ERR, "Cannot open TUN/TAP dev %s", tunname); - } - - set_nonblock (tt->fd); - set_cloexec (tt->fd); /* don't pass fd to scripts */ - msg (M_INFO, "TUN/TAP device %s opened", tunname); - - /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */ - tt->actual_name = string_alloc (dynamic_opened ? dynamic_name : dev, NULL); - } -} - -static void -close_tun_generic (struct tuntap *tt) -{ - if (tt->fd >= 0) - close (tt->fd); - if (tt->actual_name) - free (tt->actual_name); - clear_tuntap (tt); -} - -#endif - -#if defined(TARGET_LINUX) - -#ifdef HAVE_LINUX_IF_TUN_H /* New driver support */ - -#ifndef HAVE_LINUX_SOCKIOS_H -#error header file linux/sockios.h required -#endif - -#if defined(HAVE_TUN_PI) && defined(HAVE_IPHDR) && defined(HAVE_IOVEC) && defined(ETH_P_IPV6) && defined(ETH_P_IP) && defined(HAVE_READV) && defined(HAVE_WRITEV) -#define LINUX_IPV6 1 -/* #warning IPv6 ON */ -#else -#define LINUX_IPV6 0 -/* #warning IPv6 OFF */ -#endif - -#if !PEDANTIC - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - struct ifreq ifr; - - /* - * Set tt->ipv6 to true if - * (a) we have the capability of supporting --tun-ipv6, and - * (b) --tun-ipv6 was specified. - */ - ipv6_support (ipv6, LINUX_IPV6, tt); - - /* - * We handle --dev null specially, we do not open /dev/null for this. - */ - if (tt->type == DEV_TYPE_NULL) - { - open_null (tt); - } - else - { - /* - * Process --dev-node - */ - const char *node = dev_node; - if (!node) - node = "/dev/net/tun"; - - /* - * Open the interface - */ - if ((tt->fd = open (node, O_RDWR)) < 0) - { - msg (M_WARN | M_ERRNO, "Note: Cannot open TUN/TAP dev %s", node); - goto linux_2_2_fallback; - } - - /* - * Process --tun-ipv6 - */ - CLEAR (ifr); - if (!tt->ipv6) - ifr.ifr_flags = IFF_NO_PI; - -#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) - ifr.ifr_flags |= IFF_ONE_QUEUE; -#endif - - /* - * Figure out if tun or tap device - */ - if (tt->type == DEV_TYPE_TUN) - { - ifr.ifr_flags |= IFF_TUN; - } - else if (tt->type == DEV_TYPE_TAP) - { - ifr.ifr_flags |= IFF_TAP; - } - else - { - msg (M_FATAL, "I don't recognize device %s as a tun or tap device", - dev); - } - - /* - * Set an explicit name, if --dev is not tun or tap - */ - if (strcmp(dev, "tun") && strcmp(dev, "tap")) - strncpynt (ifr.ifr_name, dev, IFNAMSIZ); - - /* - * Use special ioctl that configures tun/tap device with the parms - * we set in ifr - */ - if (ioctl (tt->fd, TUNSETIFF, (void *) &ifr) < 0) - { - msg (M_WARN | M_ERRNO, "Note: Cannot ioctl TUNSETIFF %s", dev); - goto linux_2_2_fallback; - } - - msg (M_INFO, "TUN/TAP device %s opened", ifr.ifr_name); - - /* - * Try making the TX send queue bigger - */ -#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) - { - struct ifreq netifr; - int ctl_fd; - - if ((ctl_fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) - { - CLEAR (netifr); - strncpynt (netifr.ifr_name, ifr.ifr_name, IFNAMSIZ); - netifr.ifr_qlen = tt->options.txqueuelen; - if (ioctl (ctl_fd, SIOCSIFTXQLEN, (void *) &netifr) >= 0) - msg (D_OSBUF, "TUN/TAP TX queue length set to %d", tt->options.txqueuelen); - else - msg (M_WARN | M_ERRNO, "Note: Cannot set tx queue length on %s", ifr.ifr_name); - close (ctl_fd); - } - else - { - msg (M_WARN | M_ERRNO, "Note: Cannot open control socket on %s", ifr.ifr_name); - } - } -#endif - - set_nonblock (tt->fd); - set_cloexec (tt->fd); - tt->actual_name = string_alloc (ifr.ifr_name, NULL); - } - return; - - linux_2_2_fallback: - msg (M_INFO, "Note: Attempting fallback to kernel 2.2 TUN/TAP interface"); - if (tt->fd >= 0) - { - close (tt->fd); - tt->fd = -1; - } - open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt); -} - -#else - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - ASSERT (0); -} - -#endif - -#else - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt); -} - -#endif /* HAVE_LINUX_IF_TUN_H */ - -#ifdef TUNSETPERSIST - -void -tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode) -{ - struct tuntap *tt; - - ALLOC_OBJ (tt, struct tuntap); - clear_tuntap (tt); - tt->type = dev_type_enum (dev, dev_type); - open_tun (dev, dev_type, dev_node, ipv6, tt); - if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0) - msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev); - close_tun (tt); - msg (M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF")); -} - -#endif /* TUNSETPERSIST */ - -void -close_tun (struct tuntap *tt) -{ - if (tt) - { - close_tun_generic (tt); - free (tt); - } -} - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ -#if LINUX_IPV6 - if (tt->ipv6) - { - struct tun_pi pi; - struct iphdr *iph; - struct iovec vect[2]; - int ret; - - iph = (struct iphdr *)buf; - - pi.flags = 0; - - if(iph->version == 6) - pi.proto = htons(ETH_P_IPV6); - else - pi.proto = htons(ETH_P_IP); - - vect[0].iov_len = sizeof(pi); - vect[0].iov_base = π - vect[1].iov_len = len; - vect[1].iov_base = buf; - - ret = writev(tt->fd, vect, 2); - return(ret - sizeof(pi)); - } - else -#endif - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ -#if LINUX_IPV6 - if (tt->ipv6) - { - struct iovec vect[2]; - struct tun_pi pi; - int ret; - - vect[0].iov_len = sizeof(pi); - vect[0].iov_base = π - vect[1].iov_len = len; - vect[1].iov_base = buf; - - ret = readv(tt->fd, vect, 2); - return(ret - sizeof(pi)); - } - else -#endif - return read (tt->fd, buf, len); -} - -#elif defined(TARGET_SOLARIS) - -#ifndef TUNNEWPPA -#error I need the symbol TUNNEWPPA from net/if_tun.h -#endif - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - int if_fd, muxid, ppa = -1; - struct ifreq ifr; - const char *ptr; - const char *ip_node; - const char *dev_tuntap_type; - int link_type; - bool is_tun; - - ipv6_support (ipv6, false, tt); - - if (tt->type == DEV_TYPE_NULL) - { - open_null (tt); - return; - } - - if (tt->type == DEV_TYPE_TUN) - { - ip_node = "/dev/udp"; - if (!dev_node) - dev_node = "/dev/tun"; - dev_tuntap_type = "tun"; - link_type = I_PLINK; - is_tun = true; - } - else if (tt->type == DEV_TYPE_TAP) - { - ip_node = "/dev/ip"; - if (!dev_node) - dev_node = "/dev/tap"; - dev_tuntap_type = "tap"; - link_type = I_PLINK; /* was: I_LINK */ - is_tun = false; - } - else - { - msg (M_FATAL, "I don't recognize device %s as a tun or tap device", - dev); - } - - /* get unit number */ - if (*dev) - { - ptr = dev; - while (*ptr && !isdigit ((int) *ptr)) - ptr++; - ppa = atoi (ptr); - } - - if ((tt->ip_fd = open (ip_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s", ip_node); - - if ((tt->fd = open (dev_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s", dev_node); - - /* Assign a new PPA and get its unit number. */ - if ((ppa = ioctl (tt->fd, TUNNEWPPA, ppa)) < 0) - msg (M_ERR, "Can't assign new interface"); - - if ((if_fd = open (dev_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s (2)", dev_node); - - if (ioctl (if_fd, I_PUSH, "ip") < 0) - msg (M_ERR, "Can't push IP module"); - - /* Assign ppa according to the unit number returned by tun device */ - if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0) - msg (M_ERR, "Can't set PPA %d", ppa); - - if ((muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0) - msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type); - - close (if_fd); - - tt->actual_name = (char *) malloc (32); - check_malloc_return (tt->actual_name); - - openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa); - - CLEAR (ifr); - strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name)); - ifr.ifr_ip_muxid = muxid; - - if (ioctl (tt->ip_fd, SIOCSIFMUXID, &ifr) < 0) - { - ioctl (tt->ip_fd, I_PUNLINK, muxid); - msg (M_ERR, "Can't set multiplexor id"); - } - - set_nonblock (tt->fd); - set_cloexec (tt->fd); - set_cloexec (tt->ip_fd); - - msg (M_INFO, "TUN/TAP device %s opened", tt->actual_name); -} - -static void -solaris_close_tun (struct tuntap *tt) -{ - if (tt) - { - if (tt->ip_fd >= 0) - { - struct ifreq ifr; - CLEAR (ifr); - strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name)); - - if (ioctl (tt->ip_fd, SIOCGIFFLAGS, &ifr) < 0) - msg (M_WARN | M_ERRNO, "Can't get iface flags"); - - if (ioctl (tt->ip_fd, SIOCGIFMUXID, &ifr) < 0) - msg (M_WARN | M_ERRNO, "Can't get multiplexor id"); - - if (ioctl (tt->ip_fd, I_PUNLINK, ifr.ifr_ip_muxid) < 0) - msg (M_WARN | M_ERRNO, "Can't unlink interface"); - - close (tt->ip_fd); - tt->ip_fd = -1; - } - - if (tt->fd >= 0) - { - close (tt->fd); - tt->fd = -1; - } - } -} - -/* - * Close TUN device. - */ -void -close_tun (struct tuntap *tt) -{ - if (tt) - { - solaris_close_tun (tt); - - if (tt->actual_name) - free (tt->actual_name); - - clear_tuntap (tt); - free (tt); - } -} - -static void -solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual) -{ - char command_line[256]; - - openvpn_snprintf (command_line, sizeof (command_line), - IFCONFIG_PATH " %s unplumb", - actual); - - msg (M_INFO, "%s", command_line); - system_check (command_line, es, 0, "Solaris ifconfig unplumb failed"); - close_tun (tt); - msg (M_FATAL, "Solaris ifconfig failed"); -} - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - struct strbuf sbuf; - sbuf.len = len; - sbuf.buf = (char *)buf; - return putmsg (tt->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1; -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - struct strbuf sbuf; - int f = 0; - - sbuf.maxlen = len; - sbuf.buf = (char *)buf; - return getmsg (tt->fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; -} - -#elif defined(TARGET_OPENBSD) - -#if !defined(HAVE_READV) || !defined(HAVE_WRITEV) -#error openbsd build requires readv & writev library functions -#endif - -/* - * OpenBSD has a slightly incompatible TUN device from - * the rest of the world, in that it prepends a - * uint32 to the beginning of the IP header - * to designate the protocol (why not just - * look at the version field in the IP header to - * determine v4 or v6?). - * - * We strip off this field on reads and - * put it back on writes. - * - * I have not tested TAP devices on OpenBSD, - * but I have conditionalized the special - * TUN handling code described above to - * go away for TAP devices. - */ - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); - - /* Enable multicast on the interface */ - if (tt->fd >= 0) - { - struct tuninfo info; - - if (ioctl (tt->fd, TUNGIFINFO, &info) < 0) { - msg (M_WARN | M_ERRNO, "Can't get interface info: %s", - strerror(errno)); - } - - info.flags |= IFF_MULTICAST; - - if (ioctl (tt->fd, TUNSIFINFO, &info) < 0) { - msg (M_WARN | M_ERRNO, "Can't set interface info: %s", - strerror(errno)); - } - } -} - -void -close_tun (struct tuntap* tt) -{ - if (tt) - { - close_tun_generic (tt); - free (tt); - } -} - -static inline int -openbsd_modify_read_write_return (int len) -{ - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; -} - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; - - iph = (struct ip *) buf; - - if (tt->ipv6 && iph->ip_v == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); - - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return openbsd_modify_read_write_return (writev (tt->fd, iv, 2)); - } - else - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return openbsd_modify_read_write_return (readv (tt->fd, iv, 2)); - } - else - return read (tt->fd, buf, len); -} - -#elif defined(TARGET_NETBSD) - -/* - * NetBSD does not support IPv6 on tun out of the box, - * but there exists a patch. When this patch is applied, - * only two things are left to openvpn: - * 1. Activate multicasting (this has already been done - * before by the kernel, but we make sure that nobody - * has deactivated multicasting inbetween. - * 2. Deactivate "link layer mode" (otherwise NetBSD - * prepends the address family to the packet, and we - * would run into the same trouble as with OpenBSD. - */ - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); - if (tt->fd >= 0) - { - int i = IFF_POINTOPOINT|IFF_MULTICAST; - ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */ - i = 0; - ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */ - } -} - -void -close_tun (struct tuntap *tt) -{ - if (tt) - { - close_tun_generic (tt); - free (tt); - } -} - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - return read (tt->fd, buf, len); -} - -#elif defined(TARGET_FREEBSD) - -static inline int -freebsd_modify_read_write_return (int len) -{ - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; -} - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); - - if (tt->fd >= 0) - { - int i = 0; - - /* Disable extended modes */ - ioctl (tt->fd, TUNSLMODE, &i); - i = 1; - ioctl (tt->fd, TUNSIFHEAD, &i); - } -} - -void -close_tun (struct tuntap *tt) -{ - if (tt) - { - close_tun_generic (tt); - free (tt); - } -} - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; - - iph = (struct ip *) buf; - - if (tt->ipv6 && iph->ip_v == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); - - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return freebsd_modify_read_write_return (writev (tt->fd, iv, 2)); - } - else - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return freebsd_modify_read_write_return (readv (tt->fd, iv, 2)); - } - else - return read (tt->fd, buf, len); -} - -#elif defined(WIN32) - -int -tun_read_queue (struct tuntap *tt, int maxsize) -{ - if (tt->reads.iostate == IOSTATE_INITIAL) - { - DWORD len; - BOOL status; - int err; - - /* reset buf to its initial state */ - tt->reads.buf = tt->reads.buf_init; - - len = maxsize ? maxsize : BLEN (&tt->reads.buf); - ASSERT (len <= BLEN (&tt->reads.buf)); - - /* the overlapped read will signal this event on I/O completion */ - ASSERT (ResetEvent (tt->reads.overlapped.hEvent)); - - status = ReadFile( - tt->hand, - BPTR (&tt->reads.buf), - len, - &tt->reads.size, - &tt->reads.overlapped - ); - - if (status) /* operation completed immediately? */ - { - /* since we got an immediate return, we must signal the event object ourselves */ - ASSERT (SetEvent (tt->reads.overlapped.hEvent)); - - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->reads.status = 0; - - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read immediate return [%d,%d]", - (int) len, - (int) tt->reads.size); - } - else - { - err = GetLastError (); - if (err == ERROR_IO_PENDING) /* operation queued? */ - { - tt->reads.iostate = IOSTATE_QUEUED; - tt->reads.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read queued [%d]", - (int) len); - } - else /* error occurred */ - { - struct gc_arena gc = gc_new (); - ASSERT (SetEvent (tt->reads.overlapped.hEvent)); - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->reads.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read error [%d] : %s", - (int) len, - strerror_win32 (status, &gc)); - gc_free (&gc); - } - } - } - return tt->reads.iostate; -} - -int -tun_write_queue (struct tuntap *tt, struct buffer *buf) -{ - if (tt->writes.iostate == IOSTATE_INITIAL) - { - BOOL status; - int err; - - /* make a private copy of buf */ - tt->writes.buf = tt->writes.buf_init; - tt->writes.buf.len = 0; - ASSERT (buf_copy (&tt->writes.buf, buf)); - - /* the overlapped write will signal this event on I/O completion */ - ASSERT (ResetEvent (tt->writes.overlapped.hEvent)); - - status = WriteFile( - tt->hand, - BPTR (&tt->writes.buf), - BLEN (&tt->writes.buf), - &tt->writes.size, - &tt->writes.overlapped - ); - - if (status) /* operation completed immediately? */ - { - tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - - /* since we got an immediate return, we must signal the event object ourselves */ - ASSERT (SetEvent (tt->writes.overlapped.hEvent)); - - tt->writes.status = 0; - - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write immediate return [%d,%d]", - BLEN (&tt->writes.buf), - (int) tt->writes.size); - } - else - { - err = GetLastError (); - if (err == ERROR_IO_PENDING) /* operation queued? */ - { - tt->writes.iostate = IOSTATE_QUEUED; - tt->writes.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write queued [%d]", - BLEN (&tt->writes.buf)); - } - else /* error occurred */ - { - struct gc_arena gc = gc_new (); - ASSERT (SetEvent (tt->writes.overlapped.hEvent)); - tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->writes.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write error [%d] : %s", - BLEN (&tt->writes.buf), - strerror_win32 (err, &gc)); - gc_free (&gc); - } - } - } - return tt->writes.iostate; -} - -int -tun_finalize ( - HANDLE h, - struct overlapped_io *io, - struct buffer *buf) -{ - int ret = -1; - BOOL status; - - switch (io->iostate) - { - case IOSTATE_QUEUED: - status = GetOverlappedResult( - h, - &io->overlapped, - &io->size, - FALSE - ); - if (status) - { - /* successful return for a queued operation */ - if (buf) - *buf = io->buf; - ret = io->size; - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion success [%d]", ret); - } - else - { - /* error during a queued operation */ - ret = -1; - if (GetLastError() != ERROR_IO_INCOMPLETE) - { - /* if no error (i.e. just not finished yet), - then DON'T execute this code */ - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion error"); - } - } - break; - - case IOSTATE_IMMEDIATE_RETURN: - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - if (io->status) - { - /* error return for a non-queued operation */ - SetLastError (io->status); - ret = -1; - msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion non-queued error"); - } - else - { - /* successful return for a non-queued operation */ - if (buf) - *buf = io->buf; - ret = io->size; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion non-queued success [%d]", ret); - } - break; - - case IOSTATE_INITIAL: /* were we called without proper queueing? */ - SetLastError (ERROR_INVALID_FUNCTION); - ret = -1; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion BAD STATE"); - break; - - default: - ASSERT (0); - } - - if (buf) - buf->len = ret; - return ret; -} - -const struct tap_reg * -get_tap_reg (struct gc_arena *gc) -{ - HKEY adapter_key; - LONG status; - DWORD len; - struct tap_reg *first = NULL; - struct tap_reg *last = NULL; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - ADAPTER_KEY, - 0, - KEY_READ, - &adapter_key); - - if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error opening registry key: %s", ADAPTER_KEY); - - while (true) - { - char enum_name[256]; - char unit_string[256]; - HKEY unit_key; - char component_id_string[] = "ComponentId"; - char component_id[256]; - char net_cfg_instance_id_string[] = "NetCfgInstanceId"; - char net_cfg_instance_id[256]; - DWORD data_type; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - adapter_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error enumerating registry subkeys of key: %s", - ADAPTER_KEY); - - openvpn_snprintf (unit_string, sizeof(unit_string), "%s\\%s", - ADAPTER_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - unit_string, - 0, - KEY_READ, - &unit_key); - - if (status != ERROR_SUCCESS) - dmsg (D_REGISTRY, "Error opening registry key: %s", unit_string); - else - { - len = sizeof (component_id); - status = RegQueryValueEx( - unit_key, - component_id_string, - NULL, - &data_type, - component_id, - &len); - - if (status != ERROR_SUCCESS || data_type != REG_SZ) - dmsg (D_REGISTRY, "Error opening registry key: %s\\%s", - unit_string, component_id_string); - else - { - len = sizeof (net_cfg_instance_id); - status = RegQueryValueEx( - unit_key, - net_cfg_instance_id_string, - NULL, - &data_type, - net_cfg_instance_id, - &len); - - if (status == ERROR_SUCCESS && data_type == REG_SZ) - { - if (!strcmp (component_id, TAP_COMPONENT_ID)) - { - struct tap_reg *reg; - ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc); - reg->guid = string_alloc (net_cfg_instance_id, gc); - - /* link into return list */ - if (!first) - first = reg; - if (last) - last->next = reg; - last = reg; - } - } - } - RegCloseKey (unit_key); - } - ++i; - } - - RegCloseKey (adapter_key); - return first; -} - -const struct panel_reg * -get_panel_reg (struct gc_arena *gc) -{ - LONG status; - HKEY network_connections_key; - DWORD len; - struct panel_reg *first = NULL; - struct panel_reg *last = NULL; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - NETWORK_CONNECTIONS_KEY, - 0, - KEY_READ, - &network_connections_key); - - if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error opening registry key: %s", NETWORK_CONNECTIONS_KEY); - - while (true) - { - char enum_name[256]; - char connection_string[256]; - HKEY connection_key; - char name_data[256]; - DWORD name_type; - const char name_string[] = "Name"; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - network_connections_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error enumerating registry subkeys of key: %s", - NETWORK_CONNECTIONS_KEY); - - openvpn_snprintf (connection_string, sizeof(connection_string), - "%s\\%s\\Connection", - NETWORK_CONNECTIONS_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - connection_string, - 0, - KEY_READ, - &connection_key); - - if (status != ERROR_SUCCESS) - dmsg (D_REGISTRY, "Error opening registry key: %s", connection_string); - else - { - len = sizeof (name_data); - status = RegQueryValueEx( - connection_key, - name_string, - NULL, - &name_type, - name_data, - &len); - - if (status != ERROR_SUCCESS || name_type != REG_SZ) - dmsg (D_REGISTRY, "Error opening registry key: %s\\%s\\%s", - NETWORK_CONNECTIONS_KEY, connection_string, name_string); - else - { - struct panel_reg *reg; - - ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); - reg->name = string_alloc (name_data, gc); - reg->guid = string_alloc (enum_name, gc); - - /* link into return list */ - if (!first) - first = reg; - if (last) - last->next = reg; - last = reg; - } - RegCloseKey (connection_key); - } - ++i; - } - - RegCloseKey (network_connections_key); - - return first; -} - -/* - * Check that two addresses are part of the same 255.255.255.252 subnet. - */ -void -verify_255_255_255_252 (in_addr_t local, in_addr_t remote) -{ - struct gc_arena gc = gc_new (); - const unsigned int mask = 3; - const char *err = NULL; - - if (local == remote) - { - err = "must be different"; - goto error; - } - if ((local & (~mask)) != (remote & (~mask))) - { - err = "must exist within the same 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver"; - goto error; - } - if ((local & mask) == 0 - || (local & mask) == 3 - || (remote & mask) == 0 - || (remote & mask) == 3) - { - err = "cannot use the first or last address within a given 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver"; - goto error; - } - - gc_free (&gc); - return; - - error: - msg (M_FATAL, "There is a problem in your selection of --ifconfig endpoints [local=%s, remote=%s]. The local and remote VPN endpoints %s. Try '" PACKAGE " --show-valid-subnets' option for more info.", - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote, 0, &gc), - err); - gc_free (&gc); -} - -void show_valid_win32_tun_subnets (void) -{ - int i; - int col = 0; - - printf ("On Windows, point-to-point IP support (i.e. --dev tun)\n"); - printf ("is emulated by the TAP-Win32 driver. The major limitation\n"); - printf ("imposed by this approach is that the --ifconfig local and\n"); - printf ("remote endpoints must be part of the same 255.255.255.252\n"); - printf ("subnet. The following list shows examples of endpoint\n"); - printf ("pairs which satisfy this requirement. Only the final\n"); - printf ("component of the IP address pairs is at issue.\n\n"); - printf ("As an example, the following option would be correct:\n"); - printf (" --ifconfig 10.7.0.5 10.7.0.6 (on host A)\n"); - printf (" --ifconfig 10.7.0.6 10.7.0.5 (on host B)\n"); - printf ("because [5,6] is part of the below list.\n\n"); - - for (i = 0; i < 256; i += 4) - { - printf("[%3d,%3d] ", i+1, i+2); - if (++col > 4) - { - col = 0; - printf ("\n"); - } - } - if (col) - printf ("\n"); -} - -void -show_tap_win32_adapters (int msglev, int warnlev) -{ - struct gc_arena gc = gc_new (); - - bool warn_panel_null = false; - bool warn_panel_dup = false; - bool warn_tap_dup = false; - - int links; - - const struct tap_reg *tr; - const struct tap_reg *tr1; - const struct panel_reg *pr; - - 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]:"); - - /* loop through each TAP-Win32 adapter registry entry */ - for (tr = tap_reg; tr != NULL; tr = tr->next) - { - links = 0; - - /* loop through each network connections entry in the control panel */ - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (!strcmp (tr->guid, pr->guid)) - { - msg (msglev, "'%s' %s", pr->name, tr->guid); - ++links; - } - } - - if (links > 1) - { - warn_panel_dup = true; - } - else if (links == 0) - { - /* a TAP adapter exists without a link from the network - connections control panel */ - warn_panel_null = true; - msg (msglev, "[NULL] %s", tr->guid); - } - } - - /* check for TAP-Win32 adapter duplicated GUIDs */ - for (tr = tap_reg; tr != NULL; tr = tr->next) - { - for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next) - { - if (tr != tr1 && !strcmp (tr->guid, tr1->guid)) - warn_tap_dup = true; - } - } - - /* warn on registry inconsistencies */ - if (warn_tap_dup) - msg (warnlev, "WARNING: Some TAP-Win32 adapters have duplicate GUIDs"); - - if (warn_panel_dup) - msg (warnlev, "WARNING: Some TAP-Win32 adapters have duplicate links from the Network Connections control panel"); - - if (warn_panel_null) - msg (warnlev, "WARNING: Some TAP-Win32 adapters have no link from the Network Connections control panel"); - - gc_free (&gc); -} - -/* - * Confirm that GUID is a TAP-Win32 adapter. - */ -static bool -is_tap_win32 (const char *guid, const struct tap_reg *tap_reg) -{ - const struct tap_reg *tr; - - for (tr = tap_reg; tr != NULL; tr = tr->next) - { - if (guid && !strcmp (tr->guid, guid)) - return true; - } - - return false; -} - -static const char * -guid_to_name (const char *guid, const struct panel_reg *panel_reg) -{ - const struct panel_reg *pr; - - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (guid && !strcmp (pr->guid, guid)) - return pr->name; - } - - return NULL; -} - -static const char * -name_to_guid (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_win32 (pr->guid, tap_reg)) - return pr->guid; - } - - return NULL; -} - -static void -at_least_one_tap_win32 (const struct tap_reg *tap_reg) -{ - if (!tap_reg) - msg (M_FATAL, "There are no TAP-Win32 adapters on this system. You should be able to create a TAP-Win32 adapter by going to Start -> All Programs -> " PACKAGE_NAME " -> Add a new TAP-Win32 virtual ethernet adapter."); -} - -/* - * Get an adapter GUID and optional actual_name from the - * registry for the TAP device # = device_number. - */ -static const char * -get_unspecified_device_guid (const int device_number, - char *actual_name, - int actual_name_size, - const struct tap_reg *tap_reg_src, - const struct panel_reg *panel_reg_src, - struct gc_arena *gc) -{ - const struct tap_reg *tap_reg = tap_reg_src; - struct buffer ret = clear_buf (); - struct buffer actual = clear_buf (); - int i; - - ASSERT (device_number >= 0); - - /* Make sure we have at least one TAP adapter */ - if (!tap_reg) - return NULL; - - /* The actual_name output buffer may be NULL */ - if (actual_name) - { - ASSERT (actual_name_size > 0); - buf_set_write (&actual, actual_name, actual_name_size); - } - - /* Move on to specified device number */ - for (i = 0; i < device_number; i++) - { - tap_reg = tap_reg->next; - if (!tap_reg) - return NULL; - } - - /* Save Network Panel name (if exists) in actual_name */ - if (actual_name) - { - const char *act = guid_to_name (tap_reg->guid, panel_reg_src); - if (act) - buf_printf (&actual, "%s", act); - else - buf_printf (&actual, "NULL"); - } - - /* Save GUID for return value */ - ret = alloc_buf_gc (256, gc); - buf_printf (&ret, "%s", tap_reg->guid); - return BSTR (&ret); -} - -/* - * Lookup a --dev-node adapter name in the registry - * returning the GUID and optional actual_name. - */ -static const char * -get_device_guid (const char *name, - char *actual_name, - int actual_name_size, - 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 (); - - /* Make sure we have at least one TAP adapter */ - if (!tap_reg) - return NULL; - - /* The actual_name output buffer may be NULL */ - if (actual_name) - { - ASSERT (actual_name_size > 0); - buf_set_write (&actual, actual_name, actual_name_size); - } - - /* Check if GUID was explicitly specified as --dev-node parameter */ - if (is_tap_win32 (name, tap_reg)) - { - const char *act = guid_to_name (name, panel_reg); - buf_printf (&ret, "%s", name); - if (act) - buf_printf (&actual, "%s", act); - else - buf_printf (&actual, "NULL"); - return BSTR (&ret); - } - - /* Lookup TAP adapter in network connections list */ - { - const char *guid = name_to_guid (name, tap_reg, panel_reg); - if (guid) - { - buf_printf (&actual, "%s", name); - buf_printf (&ret, "%s", guid); - return BSTR (&ret); - } - } - - return NULL; -} - -/* - * Return a TAP name for netsh commands. - */ -const char * -get_netsh_id (const char *dev_node, struct gc_arena *gc) -{ - const struct tap_reg *tap_reg = get_tap_reg (gc); - const struct panel_reg *panel_reg = get_panel_reg (gc); - struct buffer actual = alloc_buf_gc (256, gc); - const char *guid; - - at_least_one_tap_win32 (tap_reg); - - if (dev_node) - { - guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); - } - else - { - guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); - - if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Win32 adapter */ - guid = NULL; - } - - if (!guid) - return "NULL"; /* not found */ - else if (strcmp (BPTR (&actual), "NULL")) - return BPTR (&actual); /* control panel name */ - else - return guid; /* no control panel name, return GUID instead */ -} - -/* - * Get adapter info list - */ -const IP_ADAPTER_INFO * -get_adapter_info_list (struct gc_arena *gc) -{ - ULONG size = 0; - IP_ADAPTER_INFO *pi = NULL; - DWORD status; - - if ((status = GetAdaptersInfo (NULL, &size)) != ERROR_BUFFER_OVERFLOW) - { - msg (M_INFO, "GetAdaptersInfo #1 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - else - { - pi = (PIP_ADAPTER_INFO) gc_malloc (size, false, gc); - if ((status = GetAdaptersInfo (pi, &size)) == NO_ERROR) - return pi; - else - { - msg (M_INFO, "GetAdaptersInfo #2 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - } - return pi; -} - -static const IP_INTERFACE_INFO * -get_interface_info_list (struct gc_arena *gc) -{ - ULONG size = 0; - IP_INTERFACE_INFO *ii = NULL; - DWORD status; - - if ((status = GetInterfaceInfo (NULL, &size)) != ERROR_INSUFFICIENT_BUFFER) - { - msg (M_INFO, "GetInterfaceInfo #1 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - else - { - ii = (PIP_INTERFACE_INFO) gc_malloc (size, false, gc); - if ((status = GetInterfaceInfo (ii, &size)) == NO_ERROR) - return ii; - else - { - msg (M_INFO, "GetInterfaceInfo #2 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - } - return ii; -} - -static const IP_ADAPTER_INDEX_MAP * -get_interface_info (DWORD index, struct gc_arena *gc) -{ - const IP_INTERFACE_INFO *list = get_interface_info_list (gc); - if (list) - { - int i; - for (i = 0; i < list->NumAdapters; ++i) - { - const IP_ADAPTER_INDEX_MAP *inter = &list->Adapter[i]; - if (index == inter->Index) - return inter; - } - } - return NULL; -} - -/* - * Given an adapter index, return a pointer to the - * IP_ADAPTER_INFO structure for that adapter. - */ - -static const IP_ADAPTER_INFO * -get_adapter (const IP_ADAPTER_INFO *ai, DWORD index) -{ - if (ai && index != (DWORD)~0) - { - const IP_ADAPTER_INFO *a; - - /* find index in the linked list */ - for (a = ai; a != NULL; a = a->Next) - { - if (a->Index == index) - return a; - } - } - return NULL; -} - -static const IP_ADAPTER_INFO * -get_adapter_info (DWORD index, struct gc_arena *gc) -{ - return get_adapter (get_adapter_info_list (gc), index); -} - -static int -get_adapter_n_ip_netmask (const IP_ADAPTER_INFO *ai) -{ - if (ai) - { - int n = 0; - const IP_ADDR_STRING *ip = &ai->IpAddressList; - - while (ip) - { - ++n; - ip = ip->Next; - } - return n; - } - else - return 0; -} - -static bool -get_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const int n, in_addr_t *ip, in_addr_t *netmask) -{ - bool ret = false; - *ip = 0; - *netmask = 0; - - if (ai) - { - const IP_ADDR_STRING *iplist = &ai->IpAddressList; - int i = 0; - - while (iplist) - { - if (i == n) - break; - ++i; - iplist = iplist->Next; - } - - if (iplist) - { - const unsigned int getaddr_flags = GETADDR_HOST_ORDER; - const char *ip_str = iplist->IpAddress.String; - const char *netmask_str = iplist->IpMask.String; - bool succeed1 = false; - bool succeed2 = false; - - if (ip_str && netmask_str && strlen (ip_str) && strlen (netmask_str)) - { - *ip = getaddr (getaddr_flags, ip_str, 0, &succeed1, NULL); - *netmask = getaddr (getaddr_flags, netmask_str, 0, &succeed2, NULL); - ret = (succeed1 == true && succeed2 == true); - } - } - } - - return ret; -} - -const IP_ADAPTER_INFO * -get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list) -{ - if (list && tt) - return get_adapter (list, tt->adapter_index); - else - return NULL; -} - -bool -is_adapter_up (const struct tuntap *tt, const IP_ADAPTER_INFO *list) -{ - int i; - bool ret = false; - - const IP_ADAPTER_INFO *ai = get_tun_adapter (tt, list); - - if (ai) - { - const int n = get_adapter_n_ip_netmask (ai); - - /* loop once for every IP/netmask assigned to adapter */ - for (i = 0; i < n; ++i) - { - in_addr_t ip, netmask; - if (get_adapter_ip_netmask (ai, i, &ip, &netmask)) - { - if (tt->local && tt->adapter_netmask) - { - /* wait for our --ifconfig parms to match the actual adapter parms */ - if (tt->local == ip && tt->adapter_netmask == netmask) - ret = true; - } - else - { - /* --ifconfig was not defined, maybe using a real DHCP server */ - if (ip && netmask) - ret = true; - } - } - } - } - else - ret = true; /* this can occur when TAP adapter is bridged */ - - return ret; -} - -bool -is_ip_in_adapter_subnet (const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask) -{ - int i; - bool ret = false; - - if (highest_netmask) - *highest_netmask = 0; - - if (ai) - { - const int n = get_adapter_n_ip_netmask (ai); - for (i = 0; i < n; ++i) - { - in_addr_t adapter_ip, adapter_netmask; - if (get_adapter_ip_netmask (ai, i, &adapter_ip, &adapter_netmask)) - { - if (adapter_ip && adapter_netmask && (ip & adapter_netmask) == (adapter_ip & adapter_netmask)) - { - if (highest_netmask && adapter_netmask > *highest_netmask) - *highest_netmask = adapter_netmask; - ret = true; - } - } - } - } - return ret; -} - -DWORD -adapter_index_of_ip (const IP_ADAPTER_INFO *list, const in_addr_t ip, int *count) -{ - struct gc_arena gc = gc_new (); - DWORD ret = ~0; - in_addr_t highest_netmask = 0; - bool first = true; - - if (count) - *count = 0; - - while (list) - { - in_addr_t hn; - - if (is_ip_in_adapter_subnet (list, ip, &hn)) - { - if (first || hn > highest_netmask) - { - highest_netmask = hn; - if (count) - *count = 1; - ret = list->Index; - first = false; - } - else if (hn == highest_netmask) - { - if (count) - ++*count; - } - } - list = list->Next; - } - - dmsg (D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d", - print_in_addr_t (ip, 0, &gc), - print_in_addr_t (highest_netmask, 0, &gc), - (int)ret, - count ? *count : -1); - - if (ret == ~0 && count) - *count = 0; - - gc_free (&gc); - return ret; -} - -/* - * Given an adapter index, return true if the adapter - * is DHCP disabled. - */ -static bool -dhcp_disabled (DWORD index) -{ - struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc); - bool ret = false; - - if (ai && !ai->DhcpEnabled) - ret = true; - - gc_free (&gc); - return ret; -} - -/* - * Delete all temporary address/netmask pairs which were added - * to adapter (given by index) by previous calls to AddIPAddress. - */ -static void -delete_temp_addresses (DWORD index) -{ - struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *a = get_adapter_info (index, &gc); - - if (a) - { - const IP_ADDR_STRING *ip = &a->IpAddressList; - while (ip) - { - DWORD status; - const DWORD context = ip->Context; - - if ((status = DeleteIPAddress ((ULONG) context)) == NO_ERROR) - { - msg (M_INFO, "Successfully deleted previously set dynamic IP/netmask: %s/%s", - ip->IpAddress.String, - ip->IpMask.String); - } - else - { - const char *empty = "0.0.0.0"; - if (strcmp (ip->IpAddress.String, empty) - || strcmp (ip->IpMask.String, empty)) - msg (M_INFO, "NOTE: could not delete previously set dynamic IP/netmask: %s/%s (status=%u)", - ip->IpAddress.String, - ip->IpMask.String, - (unsigned int)status); - } - ip = ip->Next; - } - } - gc_free (&gc); -} - -/* - * Get interface index for use with IP Helper API functions. - */ -static DWORD -get_interface_index (const char *guid) -{ - struct gc_arena gc = gc_new (); - ULONG index; - DWORD status; - wchar_t wbuf[256]; - snwprintf (wbuf, SIZE (wbuf), L"\\DEVICE\\TCPIP_%S", guid); - wbuf [SIZE(wbuf) - 1] = 0; - if ((status = GetAdapterIndex (wbuf, &index)) != NO_ERROR) - { - msg (M_INFO, "NOTE: could not get adapter index for %S, status=%u : %s", - wbuf, - (unsigned int)status, - strerror_win32 (status, &gc)); - gc_free (&gc); - return (DWORD)~0; - } - else - { - gc_free (&gc); - return index; - } -} - -/* - * Return a string representing a PIP_ADDR_STRING - */ -static const char * -format_ip_addr_string (const IP_ADDR_STRING *ip, struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (256, gc); - while (ip) - { - buf_printf (&out, "%s", ip->IpAddress.String); - if (strlen (ip->IpMask.String)) - { - buf_printf (&out, "/"); - buf_printf (&out, "%s", ip->IpMask.String); - } - buf_printf (&out, " "); - ip = ip->Next; - } - return BSTR (&out); -} - -/* - * Show info for a single adapter - */ -static void -show_adapter (int msglev, const IP_ADAPTER_INFO *a, struct gc_arena *gc) -{ - msg (msglev, "%s", a->Description); - msg (msglev, " Index = %d", (int)a->Index); - msg (msglev, " GUID = %s", a->AdapterName); - msg (msglev, " IP = %s", format_ip_addr_string (&a->IpAddressList, gc)); - msg (msglev, " MAC = %s", format_hex_ex (a->Address, a->AddressLength, 0, 1, ":", gc)); - msg (msglev, " GATEWAY = %s", format_ip_addr_string (&a->GatewayList, gc)); - if (a->DhcpEnabled) - { - msg (msglev, " DHCP SERV = %s", format_ip_addr_string (&a->DhcpServer, gc)); - msg (msglev, " DHCP LEASE OBTAINED = %s", time_string (a->LeaseObtained, 0, false, gc)); - msg (msglev, " DHCP LEASE EXPIRES = %s", time_string (a->LeaseExpires, 0, false, gc)); - } - if (a->HaveWins) - { - msg (msglev, " PRI WINS = %s", format_ip_addr_string (&a->PrimaryWinsServer, gc)); - msg (msglev, " SEC WINS = %s", format_ip_addr_string (&a->SecondaryWinsServer, gc)); - } -} - -/* - * Show current adapter list - */ -void -show_adapters (int msglev) -{ - struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *ai = get_adapter_info_list (&gc); - - msg (msglev, "SYSTEM ADAPTER LIST"); - if (ai) - { - const IP_ADAPTER_INFO *a; - - /* find index in the linked list */ - for (a = ai; a != NULL; a = a->Next) - { - show_adapter (msglev, a, &gc); - } - } - gc_free (&gc); -} - -/* - * DHCP release/renewal - */ - -bool -dhcp_release (const struct tuntap *tt) -{ - struct gc_arena gc = gc_new (); - bool ret = false; - if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0) - { - const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc); - if (inter) - { - DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter); - if (status == NO_ERROR) - { - msg (D_TUNTAP_INFO, "TAP: DHCP address released"); - ret = true; - } - else - msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); - } - } - gc_free (&gc); - return ret; -} - -bool -dhcp_renew (const struct tuntap *tt) -{ - struct gc_arena gc = gc_new (); - bool ret = false; - if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0) - { - const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc); - if (inter) - { - DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter); - if (status == NO_ERROR) - { - msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded"); - ret = true; - } - else - msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); - } - } - gc_free (&gc); - return ret; -} - -/* - * Convert DHCP options from the command line / config file - * into a raw DHCP-format options string. - */ - -static void -write_dhcp_u8 (struct buffer *buf, const int type, const int data) -{ - if (!buf_safe (buf, 3)) - msg (M_FATAL, "write_dhcp_u8: buffer overflow building DHCP options"); - buf_write_u8 (buf, type); - buf_write_u8 (buf, 1); - buf_write_u8 (buf, data); -} - -static void -write_dhcp_u32_array (struct buffer *buf, const int type, const uint32_t *data, const unsigned int len) -{ - if (len > 0) - { - int i; - const int size = len * sizeof (uint32_t); - - if (!buf_safe (buf, 2 + size)) - msg (M_FATAL, "write_dhcp_u32_array: buffer overflow building DHCP options"); - if (size < 1 || size > 255) - msg (M_FATAL, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); - buf_write_u8 (buf, type); - buf_write_u8 (buf, size); - for (i = 0; i < len; ++i) - buf_write_u32 (buf, data[i]); - } -} - -static void -write_dhcp_str (struct buffer *buf, const int type, const char *str) -{ - const int len = strlen (str); - if (!buf_safe (buf, 2 + len)) - msg (M_FATAL, "write_dhcp_str: buffer overflow building DHCP options"); - if (len < 1 || len > 255) - msg (M_FATAL, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); - buf_write_u8 (buf, type); - buf_write_u8 (buf, len); - buf_write (buf, str, len); -} - -static void -build_dhcp_options_string (struct buffer *buf, const struct tuntap_options *o) -{ - if (o->domain) - write_dhcp_str (buf, 15, o->domain); - - if (o->netbios_scope) - write_dhcp_str (buf, 47, o->netbios_scope); - - if (o->netbios_node_type) - write_dhcp_u8 (buf, 46, o->netbios_node_type); - - write_dhcp_u32_array (buf, 6, (uint32_t*)o->dns, o->dns_len); - write_dhcp_u32_array (buf, 44, (uint32_t*)o->wins, o->wins_len); - write_dhcp_u32_array (buf, 42, (uint32_t*)o->ntp, o->ntp_len); - write_dhcp_u32_array (buf, 45, (uint32_t*)o->nbdd, o->nbdd_len); - - /* 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 */ - if (o->disable_nbt) - { - buf_write_u8 (buf, 43); - buf_write_u8 (buf, 6); /* total length field */ - buf_write_u8 (buf, 0x001); - buf_write_u8 (buf, 4); /* length of the vendor specified field */ - buf_write_u32 (buf, 0x002); - } -} - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - struct gc_arena gc = gc_new (); - char device_path[256]; - const char *device_guid = NULL; - DWORD len; - - /*netcmd_semaphore_lock ();*/ - - ipv6_support (ipv6, false, tt); - - if (tt->type == DEV_TYPE_NULL) - { - open_null (tt); - gc_free (&gc); - return; - } - else if (tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN) - { - ; - } - else - { - msg (M_FATAL|M_NOPREFIX, "Unknown virtual device type: '%s'", dev); - } - - /* - * Lookup the device name in the registry, using the --dev-node high level name. - */ - { - const struct tap_reg *tap_reg = get_tap_reg (&gc); - const struct panel_reg *panel_reg = get_panel_reg (&gc); - char guid_buffer[256]; - - at_least_one_tap_win32 (tap_reg); - - if (dev_node) - { - /* Get the device GUID for the device specified with --dev-node. */ - device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc); - - if (!device_guid) - msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node); - - /* Open Windows TAP-Win32 adapter */ - openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAPSUFFIX); - - 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 (M_ERR, "CreateFile failed on TAP device: %s", device_path); - } - 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, - guid_buffer, - sizeof (guid_buffer), - tap_reg, - panel_reg, - &gc); - - if (!device_guid) - msg (M_FATAL, "All TAP-Win32 adapters on this system are currently in use."); - - /* Open Windows TAP-Win32 adapter */ - openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAPSUFFIX); - - 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++; - } - } - - /* translate high-level device name into a device instance - GUID using the registry */ - tt->actual_name = string_alloc (guid_buffer, NULL); - } - - msg (M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path); - - /* get driver version info */ - { - ULONG info[3]; - CLEAR (info); - if (DeviceIoControl (tt->hand, TAP_IOCTL_GET_VERSION, - &info, sizeof (info), - &info, sizeof (info), &len, NULL)) - { - msg (D_TUNTAP_INFO, "TAP-Win32 Driver Version %d.%d %s", - (int) info[0], - (int) info[1], - (info[2] ? "(DEBUG)" : "")); - - } - if ( !(info[0] > TAP_WIN32_MIN_MAJOR - || (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR)) ) - msg (M_FATAL, "ERROR: This version of " PACKAGE_NAME " requires a TAP-Win32 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_WIN32_MIN_MAJOR, - TAP_WIN32_MIN_MINOR); - } - - /* get driver MTU */ - { - ULONG mtu; - if (DeviceIoControl (tt->hand, TAP_IOCTL_GET_MTU, - &mtu, sizeof (mtu), - &mtu, sizeof (mtu), &len, NULL)) - { - tt->post_open_mtu = (int) mtu; - msg (D_MTU_INFO, "TAP-Win32 MTU=%d", (int) mtu); - } - } - - /* set point-to-point mode if TUN device */ - - if (tt->type == DEV_TYPE_TUN) - { - in_addr_t ep[2]; - ep[0] = htonl (tt->local); - ep[1] = htonl (tt->remote_netmask); - if (!tt->did_ifconfig_setup) - { - msg (M_FATAL, "ERROR: --dev tun also requires --ifconfig"); - } - if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_POINT_TO_POINT, - ep, sizeof (ep), - ep, sizeof (ep), &len, NULL)) - msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun"); - } - - /* should we tell the TAP-Win32 driver to masquerade as a DHCP server as a means - of setting the adapter address? */ - if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) - { - uint32_t ep[4]; - - /* 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) - { - ep[2] = htonl (tt->remote_netmask); - if (tt->options.dhcp_masq_custom_offset) - msg (M_WARN, "WARNING: because you are using '--dev tun' mode, the '--ip-win32 dynamic [offset]' option is ignoring the offset parameter"); - } - else - { - in_addr_t dsa; /* DHCP server addr */ - - ASSERT (tt->type == DEV_TYPE_TAP); - - if (tt->options.dhcp_masq_offset < 0) - dsa = (tt->local | (~tt->adapter_netmask)) + tt->options.dhcp_masq_offset; - else - dsa = (tt->local & tt->adapter_netmask) + tt->options.dhcp_masq_offset; - - if (dsa == tt->local) - msg (M_FATAL, "ERROR: There is a clash between the --ifconfig local address and the internal DHCP server address -- both are set to %s -- please use the --ip-win32 dynamic option to choose a different free address from the --ifconfig subnet for the internal DHCP server", print_in_addr_t (dsa, 0, &gc)); - - if ((tt->local & tt->adapter_netmask) != (dsa & tt->adapter_netmask)) - msg (M_FATAL, "ERROR: --tap-win32 dynamic [offset] : offset is outside of --ifconfig subnet"); - - ep[2] = htonl (dsa); - } - - /* lease time in seconds */ - ep[3] = (uint32_t) tt->options.dhcp_lease_time; - - ASSERT (ep[3] > 0); - - if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_DHCP_MASQ, - ep, sizeof (ep), - ep, sizeof (ep), &len, NULL)) - msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a DeviceIoControl call to set TAP_IOCTL_CONFIG_DHCP_MASQ mode"); - - msg (M_INFO, "Notified TAP-Win32 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) - { - struct buffer buf = alloc_buf (256); - 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_IOCTL_CONFIG_DHCP_SET_OPT, - BPTR (&buf), BLEN (&buf), - BPTR (&buf), BLEN (&buf), &len, NULL)) - msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a TAP_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call"); - free_buf (&buf); - } - } - - /* set driver media status to 'connected' */ - { - ULONG status = TRUE; - if (!DeviceIoControl (tt->hand, TAP_IOCTL_SET_MEDIA_STATUS, - &status, sizeof (status), - &status, sizeof (status), &len, NULL)) - msg (M_WARN, "WARNING: The TAP-Win32 driver rejected a TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); - } - - /* possible wait for adapter to come up */ - { - int s = tt->options.tap_sleep; - if (s > 0) - { - msg (M_INFO, "Sleeping for %d seconds...", s); - openvpn_sleep (s); - } - } - - /* possibly use IP Helper API to set IP address on adapter */ - { - DWORD index = get_interface_index (device_guid); - tt->adapter_index = index; - - /* flush arp cache */ - if (index != (DWORD)~0) - { - DWORD status; - - if ((status = FlushIpNetTable (index)) == NO_ERROR) - msg (M_INFO, "Successful ARP Flush on interface [%u] %s", - (unsigned int)index, - device_guid); - else - msg (M_WARN, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s", - (unsigned int)index, - device_guid, - (unsigned int)status, - strerror_win32 (status, &gc)); - } - - /* - * If the TAP-Win32 driver is masquerading as a DHCP server - * make sure the TCP/IP properties for the adapter are - * set correctly. - */ - if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) - { - /* check dhcp enable status */ - if (dhcp_disabled (index)) - msg (M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'"); - - /* force an explicit DHCP lease renewal on TAP adapter? */ - if (tt->options.dhcp_pre_release) - dhcp_release (tt); - if (tt->options.dhcp_renew) - dhcp_renew (tt); - } - - 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')"; - - /* couldn't get adapter index */ - if (index == (DWORD)~0) - { - msg (M_FATAL, "ERROR: unable to get adapter index for interface %s -- %s", - device_guid, - error_suffix); - } - - /* check dhcp enable status */ - if (dhcp_disabled (index)) - msg (M_WARN, "NOTE: You have selected (explicitly or by default) '--ip-win32 ipapi', which has a better chance of working correctly if the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'"); - - /* delete previously added IP addresses which were not - 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) - 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; - } - } - /*netcmd_semaphore_release ();*/ - gc_free (&gc); -} - -const char * -tap_win32_getinfo (const struct tuntap *tt, struct gc_arena *gc) -{ - if (tt && tt->hand != NULL) - { - struct buffer out = alloc_buf_gc (256, gc); - DWORD len; - if (DeviceIoControl (tt->hand, TAP_IOCTL_GET_INFO, - BSTR (&out), BCAP (&out), - BSTR (&out), BCAP (&out), - &len, NULL)) - { - return BSTR (&out); - } - } - return NULL; -} - -void -tun_show_debug (struct tuntap *tt) -{ - if (tt && tt->hand != NULL) - { - struct buffer out = alloc_buf (1024); - DWORD len; - while (DeviceIoControl (tt->hand, TAP_IOCTL_GET_LOG_LINE, - BSTR (&out), BCAP (&out), - BSTR (&out), BCAP (&out), - &len, NULL)) - { - msg (D_TAP_WIN32_DEBUG, "TAP-Win32: %s", BSTR (&out)); - } - free_buf (&out); - } -} - -void -close_tun (struct tuntap *tt) -{ - struct gc_arena gc = gc_new (); - - if (tt) - { -#if 1 - if (tt->ipapi_context_defined) - { - DWORD status; - if ((status = DeleteIPAddress (tt->ipapi_context)) != NO_ERROR) - { - msg (M_WARN, "Warning: DeleteIPAddress[%u] failed on TAP-Win32 adapter, status=%u : %s", - (unsigned int)tt->ipapi_context, - (unsigned int)status, - strerror_win32 (status, &gc)); - } - } -#endif - - if (tt->options.dhcp_release) - dhcp_release (tt); - - if (tt->hand != NULL) - { - dmsg (D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Win32 adapter"); - if (!CancelIo (tt->hand)) - msg (M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Win32 adapter"); - } - - dmsg (D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Win32 adapter"); - overlapped_io_close (&tt->reads); - - dmsg (D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Win32 adapter"); - overlapped_io_close (&tt->writes); - - if (tt->hand != NULL) - { - dmsg (D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Win32 adapter"); - if (!CloseHandle (tt->hand)) - msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Win32 adapter"); - } - - if (tt->actual_name) - free (tt->actual_name); - - clear_tuntap (tt); - free (tt); - } - gc_free (&gc); -} - -/* - * Convert --ip-win32 constants between index and ascii form. - */ - -struct ipset_names { - const char *short_form; -}; - -/* Indexed by IPW32_SET_x */ -static const struct ipset_names ipset_names[] = { - {"manual"}, - {"netsh"}, - {"ipapi"}, - {"dynamic"} -}; - -int -ascii2ipset (const char* name) -{ - int i; - ASSERT (IPW32_SET_N == SIZE (ipset_names)); - for (i = 0; i < IPW32_SET_N; ++i) - if (!strcmp (name, ipset_names[i].short_form)) - return i; - return -1; -} - -const char * -ipset2ascii (int index) -{ - ASSERT (IPW32_SET_N == SIZE (ipset_names)); - if (index < 0 || index >= IPW32_SET_N) - return "[unknown --ip-win32 type]"; - else - return ipset_names[index].short_form; -} - -const char * -ipset2ascii_all (struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (256, gc); - int i; - - ASSERT (IPW32_SET_N == SIZE (ipset_names)); - for (i = 0; i < IPW32_SET_N; ++i) - { - if (i) - buf_printf(&out, " "); - buf_printf(&out, "[%s]", ipset2ascii(i)); - } - return BSTR (&out); -} - -#else /* generic */ - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) -{ - open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt); -} - -void -close_tun (struct tuntap* tt) -{ - if (tt) - { - close_tun_generic (tt); - free (tt); - } -} - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - return read (tt->fd, buf, len); -} - -#endif |