From patchwork Wed Nov 20 03:59:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 931 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id iBpCG0FV1V1IJAAAIUCqbw for ; Wed, 20 Nov 2019 10:01:21 -0500 Received: from proxy3.mail.ord1c.rsapps.net ([172.28.255.1]) by director11.mail.ord1d.rsapps.net with LMTP id OJO6GkFV1V09HQAAvGGmqA ; Wed, 20 Nov 2019 10:01:21 -0500 Received: from smtp6.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy3.mail.ord1c.rsapps.net with LMTP id kHBxGkFV1V3NUgAANIxBXg ; Wed, 20 Nov 2019 10:01:21 -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: smtp6.gate.ord1c.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: 969f1210-0ba6-11ea-bdbc-bc305bf03f9c-1-1 Received: from [216.105.38.7] ([216.105.38.7:49090] helo=lists.sourceforge.net) by smtp6.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 87/7D-27675-93555DD5; Wed, 20 Nov 2019 10:01:20 -0500 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1iXRSv-0005z7-0K; Wed, 20 Nov 2019 15:00:21 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1iXRSt-0005yz-1K for openvpn-devel@lists.sourceforge.net; Wed, 20 Nov 2019 15:00:19 +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=J9MmcqYIFpczy7Qvl+VYRo+WG8M3IjiwElA5qB93f2I=; b=SiOtUd9StdwuoC8JFmK7aiDnoz yKSE3/9oKyTaHCWc0I6eevc3PoJ+z2QAQsbZZzyUPvUtbHUH3ksdgiOASvn9K4iJesucaJWAcb647 mPm78IeaFt0F5gN4tJfFJefe3dA6TWIm69Edhq+GCPh0AguakdWMLnnQ/yG52KiDDrpk=; 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=J9MmcqYIFpczy7Qvl+VYRo+WG8M3IjiwElA5qB93f2I=; b=YLDYCg/ROdMXdn52RnQ8OLA14J c9Gic6dxXOHMuucwA6ncXh+fnKFHpOPr0B9MH1nF6kcvusSJ3wOFR7w93dMHnNa9Fg4mj8h08blQT Q0INmAjXvKRuqM7cZTWJG75BfsoA+kBbriqEvvW07cqq/xhF+OTwQSU6p0g1uB99Lp9k=; Received: from mail-lj1-f193.google.com ([209.85.208.193]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.2) id 1iXRSq-007HNC-RD for openvpn-devel@lists.sourceforge.net; Wed, 20 Nov 2019 15:00:18 +0000 Received: by mail-lj1-f193.google.com with SMTP id q2so27907150ljg.7 for ; Wed, 20 Nov 2019 07:00:16 -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=J9MmcqYIFpczy7Qvl+VYRo+WG8M3IjiwElA5qB93f2I=; b=ZPBcLAYq3rInt06AKX2k2dxdA4ui5KqwRuni3v3nY7kCDTC1rTkqhSpTUT4eczEv69 j3R+lDMUU0ab0xi6E19nwL6yWZh0Ux997kRUj+ixcoFsmvtWj/Dfau8fmobvKMuxkjXw moIucNcfqKNMUmgckN7lCs0ja6pJdc4kF9QrZWUb0roIt71hffPuhmcE03+0CfSuzR/w mMSTDvygaj4DH1IBRxdtvazg8LSB4pD6v8bgTOGqileN9C6vRk11umNjqnW4/mMsnRvy wKAp1fk0Gsnf/bCNKs1fW9V3rY2/he2YAMX8/GLUvRpSp/QSGJIR85C7d+J34+ncxNGi AkIg== 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=J9MmcqYIFpczy7Qvl+VYRo+WG8M3IjiwElA5qB93f2I=; b=ZmBVYesoT/LUMzaSQtNNNc9/llD2I7QsvWqBiC9RQ3BBJzXQRdX4qyZlyiAAe5HqPV jKP6F9ndB/VaNGIbaOCep+XCnySN5JLTYMtYWAMmWxxDrKeraTqK1y2pK18eRI6M/df0 QlX91tNShJaaOSy9WIm5Z9Sx9Whud+gvAqgngxrrbo69/mvZXB9Mz7SABtmh0IQQ5qja gLqAQ+9miRxgEH7HA0phIGnaqJdB8zZkCYRaYRTe2QmCgYFjZ6yXwhxLIM7ulrjZQe7D KAzOv3iTm8cMhEDW9EiDqWlMA72/p+y4E2NmVeLfDQxo9o653VNUgYrXP1cxie/QJ00/ IcxQ== X-Gm-Message-State: APjAAAUZA7lEWb0Jlz4xslBP0+re7qeKzGBNF2cQ08lUAmHlgIrghZXf UQk+nTSpCitmBMPW4mydkzK1TB2lLiU= X-Google-Smtp-Source: APXvYqwIIslh5ausg4dBfob81SeN2L5F7ljeqH3zp7ZHkD3cS/80Vp9JUqPbpoU/+aaS2wXj+xiBQw== X-Received: by 2002:a2e:5c46:: with SMTP id q67mr3080664ljb.42.1574262009165; Wed, 20 Nov 2019 07:00:09 -0800 (PST) Received: from LAPTOP-4L3N7KFS.localdomain (dmczdm3mgdrzqc9ydzt-4.rev.dnainternet.fi. [2001:14bb:50:a835:5d45:1ba8:d174:3a4]) by smtp.gmail.com with ESMTPSA id u4sm11998955ljj.87.2019.11.20.07.00.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Nov 2019 07:00:08 -0800 (PST) From: Lev Stipakov To: openvpn-devel@lists.sourceforge.net Date: Wed, 20 Nov 2019 16:59:52 +0200 Message-Id: <20191120145952.303-1-lstipakov@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191112132637.1290-1-lstipakov@gmail.com> References: <20191112132637.1290-1-lstipakov@gmail.com> 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 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.208.193 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.208.193 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: 1iXRSq-007HNC-RD Subject: [Openvpn-devel] [PATCH v4 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 --- While v2 has been ACKed, it had to be rebased on top of previous patch in series, which required some manual work. 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 | 105 +++++++++++++++ src/openvpn/tun.c | 82 ++++++++++-- src/openvpn/tun.h | 3 + src/openvpn/win32.c | 27 ---- src/openvpn/win32.h | 47 ------- src/openvpnserv/Makefile.am | 3 +- src/openvpnserv/interactive.c | 141 +++++++++++++++++++- src/openvpnserv/openvpnserv.vcxproj | 2 + src/openvpnserv/openvpnserv.vcxproj.filters | 6 + 14 files changed, 400 insertions(+), 94 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..5c81e0d2 --- /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(send_ring->data); + rr.send.tail_moved = send_tail_moved; + + rr.receive.ring = receive_ring; + rr.receive.ring_size = sizeof(receive_ring->data); + rr.receive.tail_moved = receive_tail_moved; + + res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), + NULL, 0, &bytes_returned, NULL); + + return res == TRUE; +} + +#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..5095af5b --- /dev/null +++ b/src/openvpn/ring_buffer.h @@ -0,0 +1,105 @@ +/* + * 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_RING_FRAMING_SIZE 12 +#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 + WINTUN_RING_FRAMING_SIZE]; +}; + +/** + * 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 6522c6b6..f97dc936 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -799,17 +799,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 { @@ -5634,6 +5646,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) { @@ -6228,9 +6278,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 { @@ -6395,13 +6456,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 784bde1a..f9970900 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" @@ -184,6 +185,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 5c168b3b..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(send_ring->data); - rr.send.tail_moved = send_tail_moved; - - rr.receive.ring = receive_ring; - rr.receive.ring_size = sizeof(receive_ring->data); - rr.receive.tail_moved = receive_tail_moved; - - res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), - NULL, 0, &bytes_returned, NULL); - - return res == TRUE; -} - #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index f6d45bdc..4b508c56 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -325,54 +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_RING_FRAMING_SIZE 12 -#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 + WINTUN_RING_FRAMING_SIZE]; -}; - -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 +