From patchwork Tue Dec 17 01:50:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 943 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.27.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id CFfvGn/P+F3LWgAAIUCqbw for ; Tue, 17 Dec 2019 07:52:15 -0500 Received: from proxy9.mail.iad3a.rsapps.net ([172.27.255.1]) by director12.mail.ord1d.rsapps.net with LMTP id YNlYGH/P+F2IWAAAIasKDg ; Tue, 17 Dec 2019 07:52:15 -0500 Received: from smtp3.gate.iad3a ([172.27.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy9.mail.iad3a.rsapps.net with LMTP id EHktEn/P+F1TMgAAGuSQww ; Tue, 17 Dec 2019 07:52:15 -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: smtp3.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: 0c51d846-20cc-11ea-a868-525400af4d07-1-1 Received: from [216.105.38.7] ([216.105.38.7:38330] helo=lists.sourceforge.net) by smtp3.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id DB/44-10436-E7FC8FD5; Tue, 17 Dec 2019 07:52:15 -0500 Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1ihCJn-0005Vi-4E; Tue, 17 Dec 2019 12:51:15 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ihCJl-0005VX-V9 for openvpn-devel@lists.sourceforge.net; Tue, 17 Dec 2019 12:51:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To: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:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=ou7vLWcYkcEhVHETAoKHKeugngvOKd9Qwsc5jv3Ie0I=; b=afo58O2o8o5I7YY+T8Xvly2stx VAsLckrQkxfjg3ohux/OEeQQTmt7oaL2pYkIDzbdf7UMil966Mw3WG5sasoqQV8T+xVotgbF7OOtU sJEoffarlV19jUBK0xFXMDT/IcsNwvWPP7dEZIyKa2kfKs3cc0pG+xnY7el0u+Y80lgw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To: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:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ou7vLWcYkcEhVHETAoKHKeugngvOKd9Qwsc5jv3Ie0I=; b=G2y+QgNEXf8XHF0m9u612ZMhA0 TzNfLkBcqUGayLoTjeq3Ih3zQL9Jxjv+VHj9JgGw4RQKGqf7zAQns6INRJt6f8zgtiStGTTSV8BRS 8Hbk+RbtvKAOOx9T8L98MtgiFyyAP60UNXY1I+7Z2TIiaegawgrwKTJSfctu0JvoSNYA=; Received: from mail-wr1-f66.google.com ([209.85.221.66]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.2) id 1ihCJi-007biV-6m for openvpn-devel@lists.sourceforge.net; Tue, 17 Dec 2019 12:51:13 +0000 Received: by mail-wr1-f66.google.com with SMTP id w15so11193897wru.4 for ; Tue, 17 Dec 2019 04:51:09 -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:in-reply-to:references; bh=ou7vLWcYkcEhVHETAoKHKeugngvOKd9Qwsc5jv3Ie0I=; b=OUc3bN+DUwYXaL30+483rPXRnMqqSWPHKv/xIiLT5vPO/WRwPcS8A0m/50tJyeVPpC iaDDU19by3WumFWA61yyMIlr8OAG9hMK7I4TzncgSJVfhWqpmOHvbLoDjV7Z107d3Jqe nYkoZeL2QGprf96gq4GeA1rTsWI4PPq3ayRPgb7GO8DkciZV7zQBXr5I3YcqIdxfloK+ pxJQabrCbfr31dyro0NtUh3GKZHSBzYH/gpWlASc8ch0x1oPDgK2kf3caciURB5eLKn6 OzXoAA1QmSlJuklRJ2DkmI4SnV2ht710uTS2QYMHYY4WRlkID6bpQ5nRziXqQVzTQu7f +qdg== 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:in-reply-to :references; bh=ou7vLWcYkcEhVHETAoKHKeugngvOKd9Qwsc5jv3Ie0I=; b=k8Avd57egEH1JQhyAb7MqQ0iLRP9Uyhj018CIlmky5Bq75nZ9xbmRPQsmj3Iah8Nsg xKyYrI94gz7Lpee/dap/w/5AoTEGuTLgklIJBulnPibdkzzLByRNlKBo7E6IDqLwNVNT 7jBBN3sOmrtuvCryJ5UHkFea9nPieKgVLuVOWvLGBWSe8PVH9q9ZE+kbxADEiTl3yT1R m/+JlVZkYD5mzl4KBIQEhYE6sGittlSyCrHtOEghz/3Ok3VDw5UahjIrqEQBTaq1WI/A 8mIJ2o1bRnaV8KWe51JBa5wHsiaeNFAFoZhbcT35OqfbLTV9QVhy5RfvQfDqDu/48RQ7 3onA== X-Gm-Message-State: APjAAAWYYbcTv14aLJZExtVo212HXYlUd4kml8UrkgS9sdHeOUrJyTcZ VscP0dtHofXTyzDRbLfKPw9gwgU5b44= X-Google-Smtp-Source: APXvYqx9tpxG3Cp9jVrR/7E2t0A13xv4IkTUwvkxbSY0esTGZuGlnuPQIxBPWN5D9jYUlhn1qrezZw== X-Received: by 2002:adf:fc4b:: with SMTP id e11mr36624505wrs.326.1576587063024; Tue, 17 Dec 2019 04:51:03 -0800 (PST) Received: from LAPTOP-4L3N7KFS.panoulu.local ([2a00:1d50:3:0:1cfb:e3cd:f7ce:f15a]) by smtp.gmail.com with ESMTPSA id 60sm25744057wrn.86.2019.12.17.04.51.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Dec 2019 04:51:02 -0800 (PST) From: Lev Stipakov To: openvpn-devel@lists.sourceforge.net Date: Tue, 17 Dec 2019 14:50:41 +0200 Message-Id: <20191217125041.207-1-lstipakov@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191120145952.303-1-lstipakov@gmail.com> References: <20191120145952.303-1-lstipakov@gmail.com> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.221.66 listed in list.dnswl.org] 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: makefile.am] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.221.66 listed in wl.mailspike.net] -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: 1ihCJi-007biV-6m Subject: [Openvpn-devel] [PATCH v5 5/7] wintun: interactive service support 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 Wintun requires ring buffers registration to be performed by privileged process. In order to use openvpn with wintun by non-Administrator, we need to use interactive service and shared memory to register buffers. Openvpn process creates memory mapping object and event for send and receive ring and passes handles to interactive service. There handles are duplicated and memory mapped object is mapped into the address space of service process. Then address of mapped view and event handle is passed to wintun kernel driver. After interactive service preformed registration, openvpn process maps memory mapped object into own address space. Thus mapped views in openvpn and service process represent the same memory region. Signed-off-by: Lev Stipakov Acked-by: Simon Rozman --- While v2 has been ACKed, it had to be rebased on top of previous patch in series, which required some manual work. v5: - rebased on top of [PATCH v8 4/7] wintun: ring buffers based I/O (fixed struct tun_ring layout and made DeviceIoControl result check more robust) v4: - rebased on top of [PATCH v5 4/7] "wintun: ring buffers based I/O" v3: - rebased on top of [PATCH v4 4/7] "wintun: ring buffers based I/O" - added doxygen comments to ring_buffer.h v2: - rebased on top of master include/openvpn-msg.h | 10 ++ src/openvpn/Makefile.am | 2 +- src/openvpn/openvpn.vcxproj | 2 + src/openvpn/openvpn.vcxproj.filters | 8 +- src/openvpn/ring_buffer.c | 56 ++++++++ src/openvpn/ring_buffer.h | 104 +++++++++++++++ src/openvpn/tun.c | 82 ++++++++++-- src/openvpn/tun.h | 3 + src/openvpn/win32.c | 27 ---- src/openvpn/win32.h | 46 ------- src/openvpnserv/Makefile.am | 3 +- src/openvpnserv/interactive.c | 141 +++++++++++++++++++- src/openvpnserv/openvpnserv.vcxproj | 2 + src/openvpnserv/openvpnserv.vcxproj.filters | 6 + 14 files changed, 399 insertions(+), 93 deletions(-) create mode 100644 src/openvpn/ring_buffer.c create mode 100644 src/openvpn/ring_buffer.h diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 66177a21..3ed62069 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -39,6 +39,7 @@ typedef enum { msg_del_block_dns, msg_register_dns, msg_enable_dhcp, + msg_register_ring_buffers } message_type_t; typedef struct { @@ -117,4 +118,13 @@ typedef struct { interface_t iface; } enable_dhcp_message_t; +typedef struct { + message_header_t header; + HANDLE device; + HANDLE send_ring_handle; + HANDLE receive_ring_handle; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; +} register_ring_buffers_message_t; + #endif /* ifndef OPENVPN_MSG_H_ */ diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a091ffc2..d1bb99c2 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -138,6 +138,6 @@ openvpn_LDADD = \ $(OPTIONAL_SYSTEMD_LIBS) \ $(OPTIONAL_DL_LIBS) if WIN32 -openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h +openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h ring_buffer.c ring_buffer.h openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi endif diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 7446d97d..614d720a 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -181,6 +181,7 @@ + @@ -265,6 +266,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index 653e892c..41e62d14 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -240,6 +240,9 @@ Source Files + + Source Files + @@ -500,10 +503,13 @@ Header Files + + Header Files + Resource Files - \ No newline at end of file + diff --git a/src/openvpn/ring_buffer.c b/src/openvpn/ring_buffer.c new file mode 100644 index 00000000..8c81dc46 --- /dev/null +++ b/src/openvpn/ring_buffer.c @@ -0,0 +1,56 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2019 OpenVPN Inc + * 2019 Lev Stipakov + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "ring_buffer.h" + +#ifdef _WIN32 + +bool +register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved) +{ + struct tun_register_rings rr; + BOOL res; + DWORD bytes_returned; + + ZeroMemory(&rr, sizeof(rr)); + + rr.send.ring = send_ring; + rr.send.ring_size = sizeof(struct tun_ring); + rr.send.tail_moved = send_tail_moved; + + rr.receive.ring = receive_ring; + rr.receive.ring_size = sizeof(struct tun_ring); + rr.receive.tail_moved = receive_tail_moved; + + res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), + NULL, 0, &bytes_returned, NULL); + + return res != FALSE; +} + +#endif /* ifdef _WIN32 */ \ No newline at end of file diff --git a/src/openvpn/ring_buffer.h b/src/openvpn/ring_buffer.h new file mode 100644 index 00000000..3522c984 --- /dev/null +++ b/src/openvpn/ring_buffer.h @@ -0,0 +1,104 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2019 OpenVPN Inc + * 2019 Lev Stipakov + * + * 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; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef _WIN32 +#ifndef OPENVPN_RING_BUFFER_H +#define OPENVPN_RING_BUFFER_H + +#include +#include + +#include +#include + +/* + * Values below are taken from Wireguard Windows client + * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14 + */ +#define WINTUN_RING_CAPACITY 0x800000 +#define WINTUN_RING_TRAILING_BYTES 0x10000 +#define WINTUN_MAX_PACKET_SIZE 0xffff +#define WINTUN_PACKET_ALIGN 4 + +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +/** + * Wintun ring buffer + * See https://github.com/WireGuard/wintun#ring-layout + */ +struct tun_ring +{ + volatile ULONG head; + volatile ULONG tail; + volatile LONG alertable; + UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; +}; + +/** + * Struct for ring buffers registration + * See https://github.com/WireGuard/wintun#registering-rings + */ +struct tun_register_rings +{ + struct + { + ULONG ring_size; + struct tun_ring *ring; + HANDLE tail_moved; + } send, receive; +}; + +struct TUN_PACKET_HEADER +{ + uint32_t size; +}; + +struct TUN_PACKET +{ + uint32_t size; + UCHAR data[WINTUN_MAX_PACKET_SIZE]; +}; + +/** + * Registers ring buffers used to exchange data between + * userspace openvpn process and wintun kernel driver, + * see https://github.com/WireGuard/wintun#registering-rings + * + * @param device handle to opened wintun device + * @param send_ring pointer to send ring + * @param receive_ring pointer to receive ring + * @param send_tail_moved event set by wintun to signal openvpn + * that data is available for reading in send ring + * @param receive_tail_moved event set by openvpn to signal wintun + * that data has been written to receive ring + * @return true if registration is successful, false otherwise + */ +bool register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved); + +#endif /* ifndef OPENVPN_RING_BUFFER_H */ +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 3f66b216..77d84fb2 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -779,17 +779,29 @@ init_tun_post(struct tuntap *tt, if (tt->wintun) { - tt->wintun_send_ring = malloc(sizeof(struct tun_ring)); - tt->wintun_receive_ring = malloc(sizeof(struct tun_ring)); - if ((tt->wintun_send_ring == NULL) || (tt->wintun_receive_ring == NULL)) + tt->wintun_send_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, + 0, + sizeof(struct tun_ring), + NULL); + tt->wintun_receive_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + sizeof(struct tun_ring), + NULL); + if ((tt->wintun_send_ring_handle == NULL) || (tt->wintun_receive_ring_handle == NULL)) { msg(M_FATAL, "Cannot allocate memory for ring buffer"); } - ZeroMemory(tt->wintun_send_ring, sizeof(struct tun_ring)); - ZeroMemory(tt->wintun_receive_ring, sizeof(struct tun_ring)); tt->rw_handle.read = CreateEvent(NULL, FALSE, FALSE, NULL); tt->rw_handle.write = CreateEvent(NULL, FALSE, FALSE, NULL); + + if ((tt->rw_handle.read == NULL) || (tt->rw_handle.write == NULL)) + { + msg(M_FATAL, "Cannot create events for ring buffer"); + } } else { @@ -5604,6 +5616,44 @@ register_dns_service(const struct tuntap *tt) gc_free(&gc); } +static void +service_register_ring_buffers(const struct tuntap *tt) +{ + HANDLE msg_channel = tt->options.msg_channel; + ack_message_t ack; + struct gc_arena gc = gc_new(); + + register_ring_buffers_message_t msg = { + .header = { + msg_register_ring_buffers, + sizeof(register_ring_buffers_message_t), + 0 + }, + .device = tt->hand, + .send_ring_handle = tt->wintun_send_ring_handle, + .receive_ring_handle = tt->wintun_receive_ring_handle, + .send_tail_moved = tt->rw_handle.read, + .receive_tail_moved = tt->rw_handle.write + }; + + if (!send_msg_iservice(msg_channel, &msg, sizeof(msg), &ack, "Register ring buffers")) + { + gc_free(&gc); + return; + } + else if (ack.error_number != NO_ERROR) + { + msg(M_FATAL, "Register ring buffers failed using service: %s [status=0x%x]", + strerror_win32(ack.error_number, &gc), ack.error_number); + } + else + { + msg(M_INFO, "Ring buffers registered via service"); + } + + gc_free(&gc); +} + void fork_register_dns_action(struct tuntap *tt) { @@ -6198,9 +6248,20 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (tt->wintun) { + 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) { - /* TODO */ + service_register_ring_buffers(tt); } else { @@ -6365,13 +6426,12 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) { CloseHandle(tt->rw_handle.read); CloseHandle(tt->rw_handle.write); + UnmapViewOfFile(tt->wintun_send_ring); + UnmapViewOfFile(tt->wintun_receive_ring); + CloseHandle(tt->wintun_send_ring_handle); + CloseHandle(tt->wintun_receive_ring_handle); } - free(tt->wintun_receive_ring); - free(tt->wintun_send_ring); - - tt->wintun_receive_ring = NULL; - tt->wintun_send_ring = NULL; clear_tuntap(tt); free(tt); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 10f687c5..b0b80d1a 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -39,6 +39,7 @@ #include "proto.h" #include "misc.h" #include "networking.h" +#include "ring_buffer.h" #ifdef _WIN32 #define WINTUN_COMPONENT_ID "wintun" @@ -183,6 +184,8 @@ struct tuntap bool wintun; /* true if wintun is used instead of tap-windows6 */ int standby_iter; + HANDLE wintun_send_ring_handle; + HANDLE wintun_receive_ring_handle; struct tun_ring *wintun_send_ring; struct tun_ring *wintun_receive_ring; #else /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 24dae7d6..b2f2a19f 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1588,31 +1588,4 @@ impersonate_as_system() return true; } -bool -register_ring_buffers(HANDLE device, - struct tun_ring* send_ring, - struct tun_ring* receive_ring, - HANDLE send_tail_moved, - HANDLE receive_tail_moved) -{ - struct tun_register_rings rr; - BOOL res; - DWORD bytes_returned; - - ZeroMemory(&rr, sizeof(rr)); - - rr.send.ring = send_ring; - rr.send.ring_size = sizeof(struct tun_ring); - rr.send.tail_moved = send_tail_moved; - - rr.receive.ring = receive_ring; - rr.receive.ring_size = sizeof(struct tun_ring); - rr.receive.tail_moved = receive_tail_moved; - - res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), - NULL, 0, &bytes_returned, NULL); - - return res != FALSE; -} - #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 5fe95f47..4b508c56 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -325,53 +325,7 @@ bool send_msg_iservice(HANDLE pipe, const void *data, size_t size, int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags); -/* - * Values below are taken from Wireguard Windows client - * https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/ring_windows.go#L14 - */ -#define WINTUN_RING_CAPACITY 0x800000 -#define WINTUN_RING_TRAILING_BYTES 0x10000 -#define WINTUN_MAX_PACKET_SIZE 0xffff -#define WINTUN_PACKET_ALIGN 4 - -struct tun_ring -{ - volatile ULONG head; - volatile ULONG tail; - volatile LONG alertable; - UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES]; -}; - -struct tun_register_rings -{ - struct - { - ULONG ring_size; - struct tun_ring *ring; - HANDLE tail_moved; - } send, receive; -}; - -struct TUN_PACKET_HEADER -{ - uint32_t size; -}; - -struct TUN_PACKET -{ - uint32_t size; - UCHAR data[WINTUN_MAX_PACKET_SIZE]; -}; - -#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) - bool impersonate_as_system(); -bool register_ring_buffers(HANDLE device, - struct tun_ring *send_ring, - struct tun_ring *receive_ring, - HANDLE send_tail_moved, - HANDLE receive_tail_moved); - #endif /* ifndef OPENVPN_WIN32_H */ #endif /* ifdef _WIN32 */ diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index bc65070b..f8d3319c 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -36,4 +36,5 @@ openvpnserv_SOURCES = \ service.c service.h \ validate.c validate.h \ $(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \ - openvpnserv_resources.rc + openvpnserv_resources.rc \ + $(top_srcdir)/src/openvpn/ring_buffer.c $(top_srcdir)/src/openvpn/ring_buffer.h diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 623c3ff7..6e72a141 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -43,13 +43,15 @@ #include "openvpn-msg.h" #include "validate.h" #include "block_dns.h" +#include "ring_buffer.h" #define IO_TIMEOUT 2000 /*ms*/ -#define ERROR_OPENVPN_STARTUP 0x20000000 -#define ERROR_STARTUP_DATA 0x20000001 -#define ERROR_MESSAGE_DATA 0x20000002 -#define ERROR_MESSAGE_TYPE 0x20000003 +#define ERROR_OPENVPN_STARTUP 0x20000000 +#define ERROR_STARTUP_DATA 0x20000001 +#define ERROR_MESSAGE_DATA 0x20000002 +#define ERROR_MESSAGE_TYPE 0x20000003 +#define ERROR_REGISTER_RING_BUFFERS 0x20000004 static SERVICE_STATUS_HANDLE service; static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS }; @@ -58,6 +60,7 @@ static settings_t settings; static HANDLE rdns_semaphore = NULL; #define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */ +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) openvpn_service_t interactive_service = { interactive, @@ -100,6 +103,14 @@ typedef struct { int metric_v6; } block_dns_data_t; +typedef struct { + HANDLE send_ring_handle; + HANDLE receive_ring_handle; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; + HANDLE device; +} ring_buffer_handles_t; + static DWORD AddListItem(list_item_t **pfirst, LPVOID data) @@ -154,6 +165,26 @@ CloseHandleEx(LPHANDLE handle) return INVALID_HANDLE_VALUE; } +static HANDLE +OvpnUnmapViewOfFile(LPHANDLE handle) +{ + if (handle && *handle && *handle != INVALID_HANDLE_VALUE) + { + UnmapViewOfFile(*handle); + *handle = INVALID_HANDLE_VALUE; + } + return INVALID_HANDLE_VALUE; +} + +static void +CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles) +{ + CloseHandleEx(&ring_buffer_handles->device); + CloseHandleEx(&ring_buffer_handles->receive_tail_moved); + CloseHandleEx(&ring_buffer_handles->send_tail_moved); + OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle); + OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle); +} static HANDLE InitOverlapped(LPOVERLAPPED overlapped) @@ -1198,8 +1229,95 @@ HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp) return err; } +static DWORD +OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle) +{ + DWORD err = ERROR_SUCCESS; + + if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + err = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle")); + return err; + } + + return err; +} + +static DWORD +DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring) +{ + DWORD err = ERROR_SUCCESS; + + err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle); + if (err != ERROR_SUCCESS) + { + return err; + } + *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); + if (*ring == NULL) + { + err = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory")); + return err; + } + + return err; +} + +static DWORD +HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc, + ring_buffer_handles_t *ring_buffer_handles) +{ + DWORD err = 0; + struct tun_ring *send_ring; + struct tun_ring *receive_ring; + + CloseRingBufferHandles(ring_buffer_handles); + + err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved); + if (err != ERROR_SUCCESS) + { + return err; + } + + if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring, + ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved)) + { + MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers")); + err = ERROR_REGISTER_RING_BUFFERS; + } + + return err; +} + static VOID -HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) +HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles, + DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { DWORD read; union { @@ -1210,6 +1328,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists block_dns_message_t block_dns; dns_cfg_message_t dns; enable_dhcp_message_t dhcp; + register_ring_buffers_message_t rrb; } msg; ack_message_t ack = { .header = { @@ -1277,6 +1396,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists } break; + case msg_register_ring_buffers: + if (msg.header.size == sizeof(msg.rrb)) + { + ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles); + } + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1360,6 +1486,7 @@ RunOpenvpn(LPVOID p) WCHAR *cmdline = NULL; size_t cmdline_size; undo_lists_t undo_lists; + ring_buffer_handles_t ring_buffer_handles; SECURITY_ATTRIBUTES inheritable = { .nLength = sizeof(inheritable), @@ -1380,6 +1507,7 @@ RunOpenvpn(LPVOID p) ZeroMemory(&startup_info, sizeof(startup_info)); ZeroMemory(&undo_lists, sizeof(undo_lists)); ZeroMemory(&proc_info, sizeof(proc_info)); + ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles)); if (!GetStartupData(pipe, &sud)) { @@ -1611,7 +1739,7 @@ RunOpenvpn(LPVOID p) break; } - HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists); + HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists); } WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT); @@ -1638,6 +1766,7 @@ out: free(cmdline); DestroyEnvironmentBlock(user_env); FreeStartupData(&sud); + CloseRingBufferHandles(&ring_buffer_handles); CloseHandleEx(&proc_info.hProcess); CloseHandleEx(&proc_info.hThread); CloseHandleEx(&stdin_read); diff --git a/src/openvpnserv/openvpnserv.vcxproj b/src/openvpnserv/openvpnserv.vcxproj index 7061b7b1..c5a34b87 100644 --- a/src/openvpnserv/openvpnserv.vcxproj +++ b/src/openvpnserv/openvpnserv.vcxproj @@ -115,6 +115,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/src/openvpnserv/openvpnserv.vcxproj.filters b/src/openvpnserv/openvpnserv.vcxproj.filters index 3ce9bb24..3cb14ef6 100644 --- a/src/openvpnserv/openvpnserv.vcxproj.filters +++ b/src/openvpnserv/openvpnserv.vcxproj.filters @@ -33,6 +33,9 @@ Source Files + + Source Files + @@ -44,6 +47,9 @@ Header Files + + Header Files +