From patchwork Tue Nov 12 23:42:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 918 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.27.255.56]) by backend30.mail.ord1d.rsapps.net with LMTP id uBksG5Hey136ZQAAIUCqbw for ; Wed, 13 Nov 2019 05:44:33 -0500 Received: from proxy21.mail.iad3a.rsapps.net ([172.27.255.56]) by director9.mail.ord1d.rsapps.net with LMTP id aBcDGZHey13PBgAAalYnBA ; Wed, 13 Nov 2019 05:44:33 -0500 Received: from smtp12.gate.iad3a ([172.27.255.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy21.mail.iad3a.rsapps.net with LMTP id kIzAE5Hey11IOgAASBQwCQ ; Wed, 13 Nov 2019 05:44:33 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp12.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=gmail.com; dmarc=fail (p=none; dis=none) header.from=gmail.com X-Suspicious-Flag: YES X-Classification-ID: 9327a3e4-0602-11ea-af3c-525400068c1c-1-1 Received: from [216.105.38.7] ([216.105.38.7:37050] helo=lists.sourceforge.net) by smtp12.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 25/85-17187-09EDBCD5; Wed, 13 Nov 2019 05:44:32 -0500 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1iUq6r-0005wk-VX; Wed, 13 Nov 2019 10:42:49 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1iUq6q-0005wR-Ut for openvpn-devel@lists.sourceforge.net; Wed, 13 Nov 2019 10:42:48 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=ULWWFw972/nRrndh/5Af7yDS8nfW1A4/QX3XQSO5JEk=; b=Pgqy1Q7Dz8F9yLl1cWTgqUb2vO L2KU3VQ8IbfXZwT1tHmZEO7Q/DPf2LF8Tve+MVBpshYoE9BubPVCFusO3/D0P6G95R0AwmImHg4Qu uEX1/OcZwky23WhlPWtxaMMus+Z/j4FsKLAtfuBcxwfTNnzEElw1EGB3NwXf2VgmmvQc=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:MIME-Version: Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ULWWFw972/nRrndh/5Af7yDS8nfW1A4/QX3XQSO5JEk=; b=DNIZpDqZZf8k+k8QLq/dPXsdGU NzQQvuCArIa6rq4nlNlheti98p4wN2XzeOUGjhpiopRM3XVsmALLBpY9AMAD4SmsWN+dKQOKm5AWt LkhiEScCAIXyPNxDWqA5RQbEdEVdHbYj76FisHGCyUzFrscMclHplq20j+w1XieBWgpc=; Received: from mail-lj1-f194.google.com ([209.85.208.194]) by sfi-mx-4.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.2) id 1iUq6o-00F0y9-J7 for openvpn-devel@lists.sourceforge.net; Wed, 13 Nov 2019 10:42:48 +0000 Received: by mail-lj1-f194.google.com with SMTP id q2so1986356ljg.7 for ; Wed, 13 Nov 2019 02:42:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=ULWWFw972/nRrndh/5Af7yDS8nfW1A4/QX3XQSO5JEk=; b=dbwm/DRg3eykd4XV/nk0MjKVPRjjU62k1hwymrh2nnVrqXt4sJo98tUO9RJ1xYf7g7 d9hqF+Y8ALtfUlBELvqbgrf1lelNhTAPDT0uGcN9SQhkuRJQj1WhhE3YEcx9OmOVDSd/ N4zmPFkMfaQhSFrBABCzGXd8J2EifnuFYzcMprDtpbZsqxGmjq3/WCmTBa5mW3vJIH5q CzJPwK70Nj6XkbrtKjy42oDEprEfVQ1nuZ0RXcJTM80oo8BtALC4REcfoDIe1RgrSfyo 3sLcvS+JG22+CqBX3WX1AaUnoQ14HgCAjyOp2TSlbZ5PRCQBJfp21B7+5G2B223Kd0k2 bBxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=ULWWFw972/nRrndh/5Af7yDS8nfW1A4/QX3XQSO5JEk=; b=qq9bBboSQwkiFtA6P5nLMuLaXZjS8khBHE+UNbCnd9Grb/tK55BQxH84lQjJ9Wo0Mq DykD02xL8+o/asHKTeXFyMxTMpTjlsXN+mi2zwizAqu32pQCnGz6t5yCWuywXjkWqiPR UldZGQmen8WuSYsUs0DBPsxFx5qwKXu6Po/ZCDHfYQmuleSZseRsdmqbcybB7uJdkYBz a6546qyhaZl7nwzhYOkIpd1Qu1IxRKTT+8Ck5UuaoNRyP/4W8ckBxz6wTZANlz3X82YE PuGQi74nRnTbNLfLw86WBP14FrIMhy/GulrnzNZZWXH9vmZlmNHFYnWm1bIi1TRqwmm2 KpqQ== X-Gm-Message-State: APjAAAVhyLs+CSnHYteDZB9BoedU58Q5FHrF9lXEYHlECtNfIBquVW7w MKV5fiAZwMLvTjHqX8/o/FuN6saM4gFkZg== X-Google-Smtp-Source: APXvYqzFzFarSmNBTqYKA9Rrk/Hu7+x9c2Y3HZWrOZm2QLEXfRLWft+OSoyK0RfCC5HsE0C10g8mIQ== X-Received: by 2002:a2e:9cc4:: with SMTP id g4mr1804657ljj.99.1573641758705; Wed, 13 Nov 2019 02:42:38 -0800 (PST) Received: from LAPTOP-4L3N7KFS.localdomain (dmh5jvskrs3c95gtkxt-4.rev.dnainternet.fi. [2001:14bb:51:b278:bd0e:7dc5:dc96:89c]) by smtp.gmail.com with ESMTPSA id a8sm673594ljb.11.2019.11.13.02.42.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 13 Nov 2019 02:42:38 -0800 (PST) From: Lev Stipakov To: openvpn-devel@lists.sourceforge.net Date: Wed, 13 Nov 2019 12:42:16 +0200 Message-Id: <20191113104216.1545-1-lstipakov@gmail.com> X-Mailer: git-send-email 2.17.1 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (lstipakov[at]gmail.com) 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: openvpn.net] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.208.194 listed in wl.mailspike.net] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.208.194 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1iUq6o-00F0y9-J7 Subject: [Openvpn-devel] [PATCH] tun.c: refactor open_tun() implementation X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Lev Stipakov MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Lev Stipakov This makes Windows's tun_open() method easier to read by factoring out blocks of code, which perform certain task, into separate functions. This also minimizes inflation of if (!tt->wintun) { } blocks. While patch looks big and scary, there are no functional changes at all, just tossing code around. Signed-off-by: Lev Stipakov Acked-by: Simon Rozman --- Please note that this patch could be merged after 6/7 of wintun patch series. src/openvpn/tun.c | 961 ++++++++++++++++++++++++---------------------- 1 file changed, 509 insertions(+), 452 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 8b16cd6a..c18059c6 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -5765,591 +5765,648 @@ 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 tuntap_device_path[256]; - char *path = NULL; - 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); - 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); - - 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); + 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 (!device_guid) - { - msg(M_FATAL, "TAP-Windows adapter '%s' not found", dev_node); - } +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); + } +} - /* Open Windows TAP-Windows adapter */ - openvpn_snprintf(tuntap_device_path, sizeof(tuntap_device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); +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; - tt->hand = CreateFile(tuntap_device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0); + /* flush arp cache */ + if (index != TUN_ADAPTER_INDEX_INVALID) + { + DWORD status = -1; - if (tt->hand == INVALID_HANDLE_VALUE) + 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 (send_msg_iservice(tt->options.msg_channel, &msg, sizeof(msg), + &ack, "TUN")) { - msg(M_ERR, "CreateFile failed on TAP device: %s", tuntap_device_path); + status = ack.error_number; } } else { - int device_number = 0; - - /* Try opening all TAP devices until we find one available */ - while (true) - { - bool is_picked_device_wintun = false; - device_guid = get_unspecified_device_guid(device_number, - actual_buffer, - sizeof(actual_buffer), - tap_reg, - panel_reg, - &is_picked_device_wintun, - &gc); - - if (!device_guid) - { - msg(M_FATAL, "All %s adapters on this system are currently in use.", tt->wintun ? "wintun" : "TAP - Windows"); - } - - if (tt->wintun) - { - const struct device_instance_id_interface* dev_if; - - if (!is_picked_device_wintun) - { - /* wintun driver specified but picked adapter is not wintun, proceed to next one */ - goto next; - } - - path = NULL; - for (dev_if = device_instance_id_interface; dev_if != NULL; dev_if = dev_if->next) - { - if (strcmp(dev_if->net_cfg_instance_id, device_guid) == 0) - { - path = (char *)dev_if->device_interface_list; - break; - } - } - if (path == NULL) - { - goto next; - } - } - else - { - if (is_picked_device_wintun) - { - /* tap-windows6 driver specified but picked adapter is wintun, proceed to next one */ - goto next; - } - - /* Open Windows 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; - } - - 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) - { - msg(D_TUNTAP_INFO, "CreateFile failed on %s device: %s", tt->wintun ? "wintun" : "TAP", tuntap_device_path); - } - else - { - break; - } - - next: - 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); + if (status == NO_ERROR) + { + msg(M_INFO, "Successful ARP Flush on interface [%lu] %s", + index, + device_guid); + } + else if (status != -1) + { + msg(D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%lu] %s (status=%lu) : %s", + index, + device_guid, + status, + strerror_win32(status, &gc)); + } } - msg(M_INFO, "%s device [%s] opened: %s", tt->wintun ? "Wintun" : "TAP-WIN32", tt->actual_name, path); - tt->adapter_index = get_adapter_index(device_guid); - - /* get driver version info */ - if (!tt->wintun) + /* + * 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) { - ULONG info[3]; - CLEAR(info); - if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_VERSION, - &info, sizeof(info), - &info, sizeof(info), &len, NULL)) + /* check dhcp enable status */ + if (dhcp_status(index) == DHCP_STATUS_DISABLED) { - msg(D_TUNTAP_INFO, "TAP-Windows Driver Version %d.%d %s", - (int) info[0], - (int) info[1], - (info[2] ? "(DEBUG)" : "")); + 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) + { + dhcp_release(tt); } - if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR)) + if (tt->options.dhcp_renew) { - 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); + dhcp_renew(tt); } + } + else + { + fork_dhcp_action(tt); + } - /* 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 (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 == TUN_ADAPTER_INDEX_INVALID) { - 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_FATAL, "ERROR: unable to get adapter index for interface %s -- %s", + device_guid, + error_suffix); } - /* 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) + /* check dhcp enable status */ + if (dhcp_status(index) == DHCP_STATUS_DISABLED) { - 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] ); + 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 */ - if (!tt->wintun) - { - ULONG mtu; - if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_MTU, - &mtu, sizeof(mtu), - &mtu, sizeof(mtu), &len, NULL)) + /* 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 { - tt->post_open_mtu = (int) mtu; - msg(D_MTU_INFO, "TAP-Windows MTU=%d", (int) mtu); + 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; } - /* - * Preliminaries for setting TAP-Windows adapter TCP/IP - * properties via --ip-win32 dynamic or --ip-win32 adaptive. - */ - if (tt->did_ifconfig_setup) + gc_free(&gc); +} + +static void +wintun_register_ring_buffer(struct tuntap *tt) +{ + 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->options.ip_win32_type == IPW32_SET_DHCP_MASQ) + service_register_ring_buffers(tt); + } + else + { + if (!impersonate_as_system()) { - /* - * 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_FATAL, "ERROR: Failed to impersonate as SYSTEM, make sure process is running under privileged account"); } - else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) + if (!register_ring_buffers(tt->hand, + tt->wintun_send_ring, + tt->wintun_receive_ring, + tt->rw_handle.read, + tt->rw_handle.write)) { - /* - * 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_FATAL, "ERROR: Failed to register ring buffers: %lu", GetLastError()); + } + if (!RevertToSelf()) + { + msg(M_FATAL, "ERROR: RevertToSelf error: %lu", GetLastError()); } } +} - /* set point-to-point mode if TUN device */ +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."); + } - if ((tt->type == DEV_TYPE_TUN) && !tt->wintun) + int s = tt->options.tap_sleep; + if (s > 0) { - if (!tt->did_ifconfig_setup && !tt->did_ifconfig_ipv6_setup) - { - msg(M_FATAL, "ERROR: --dev tun also requires --ifconfig"); - } + msg(M_INFO, "Sleeping for %d seconds...", s); + management_sleep(s); + } +} - /* 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; +static void +tuntap_set_ptp(const struct tuntap *tt) +{ + DWORD len; + struct gc_arena gc = gc_new(); - ep[0] = htonl(tt->local); - ep[1] = htonl(tt->local & tt->remote_netmask); - ep[2] = htonl(tt->remote_netmask); + if (!tt->did_ifconfig_setup && !tt->did_ifconfig_ipv6_setup) + { + msg(M_FATAL, "ERROR: --dev tun also requires --ifconfig"); + } - status = DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_TUN, - ep, sizeof(ep), - ep, sizeof(ep), &len, NULL); + /* 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; - 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"); - } + 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 && !tt->wintun) - { - 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"); - } + 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"); - } - 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' */ - if (!tt->wintun) + gc_free(&gc); +} + +static void +tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid) +{ + struct gc_arena gc = gc_new(); + char *path = NULL; + char tuntap_device_path[256]; + 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) { - ULONG status = TRUE; - if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS, - &status, sizeof(status), - &status, sizeof(status), &len, NULL)) + /* 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); + + if (!*device_guid) { - msg(M_WARN, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); + msg(M_FATAL, "TAP-Windows adapter '%s' not found", dev_node); } - } - /* possible wait for adapter to come up */ - { - int s = tt->options.tap_sleep; - if (s > 0) + /* Open Windows TAP-Windows adapter */ + openvpn_snprintf(tuntap_device_path, sizeof(tuntap_device_path), "%s%s%s", + USERMODEDEVICEDIR, + *device_guid, + TAP_WIN_SUFFIX); + + tt->hand = CreateFile(tuntap_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_INFO, "Sleeping for %d seconds...", s); - management_sleep(s); + msg(M_ERR, "CreateFile failed on TAP device: %s", tuntap_device_path); } } - - /* possibly use IP Helper API to set IP address on adapter */ - if (!tt->wintun) + else { - const DWORD index = tt->adapter_index; + int device_number = 0; - /* flush arp cache */ - if (index != TUN_ADAPTER_INDEX_INVALID) + /* Try opening all TAP devices until we find one available */ + while (true) { - DWORD status = -1; + bool is_picked_device_wintun = false; + *device_guid = get_unspecified_device_guid(device_number, + actual_buffer, + sizeof(actual_buffer), + tap_reg, + panel_reg, + &is_picked_device_wintun, + &gc); - if (tt->options.msg_channel) + if (!*device_guid) + { + msg(M_FATAL, "All %s adapters on this system are currently in use.", tt->wintun ? "wintun" : "TAP - Windows"); + } + + if (tt->wintun) { - 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 (send_msg_iservice(tt->options.msg_channel, &msg, sizeof(msg), - &ack, "TUN")) + const struct device_instance_id_interface* dev_if; + + if (!is_picked_device_wintun) { - status = ack.error_number; + /* wintun driver specified but picked adapter is not wintun, proceed to next one */ + goto next; + } + + path = NULL; + for (dev_if = device_instance_id_interface; dev_if != NULL; dev_if = dev_if->next) + { + if (strcmp(dev_if->net_cfg_instance_id, *device_guid) == 0) + { + path = (char*)dev_if->device_interface_list; + break; + } + } + if (path == NULL) + { + goto next; } } else { - status = FlushIpNetTable(index); + if (is_picked_device_wintun) + { + /* tap-windows6 driver specified but picked adapter is wintun, proceed to next one */ + goto next; + } + + /* Open Windows 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; } - if (status == NO_ERROR) + 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) { - msg(M_INFO, "Successful ARP Flush on interface [%lu] %s", - index, - device_guid); + msg(D_TUNTAP_INFO, "CreateFile failed on %s device: %s", tt->wintun ? "wintun" : "TAP", tuntap_device_path); } - else if (status != -1) + else { - msg(D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%lu] %s (status=%lu) : %s", - index, - device_guid, - 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: %s", tt->wintun ? "Wintun" : "TAP-WIN32", tt->actual_name, path); + tt->adapter_index = get_adapter_index(*device_guid); + + gc_free(&gc); +} +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); - } + /* 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=%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 */ + if (tt->type == DEV_TYPE_TUN) + { + tuntap_set_ptp(tt); } - if (tt->wintun) + /* should we tell the TAP-Windows driver to masquerade as a DHCP server as a means + * of setting the adapter address? */ + if (dhcp_masq) { - 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)); + tuntap_dhcp_mask(tt, device_guid); + } - if (tt->options.msg_channel) - { - service_register_ring_buffers(tt); - } - else - { - if (!impersonate_as_system()) - { - msg(M_FATAL, "ERROR: Failed to impersonate as SYSTEM, make sure process is running under privileged account"); - } - if (!register_ring_buffers(tt->hand, - tt->wintun_send_ring, - tt->wintun_receive_ring, - tt->rw_handle.read, - tt->rw_handle.write)) - { - msg(M_FATAL, "ERROR: Failed to register ring buffers: %lu", GetLastError()); - } - if (!RevertToSelf()) - { - msg(M_FATAL, "ERROR: RevertToSelf error: %lu", GetLastError()); - } - } + /* set driver media status to 'connected' */ + tuntap_set_connected(tt); + + /* 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); + } + + tun_open_device(tt, dev_node, &device_guid); + + if (tt->wintun) + { + wintun_register_ring_buffer(tt); + } + else + { + tuntap_post_open(tt, device_guid); } /*netcmd_semaphore_release ();*/ - gc_free(&gc); } const char *