From patchwork Thu Nov 7 06:45:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 878 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director10.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net with LMTP id qNcnEghZxF2SdgAAIUCqbw for ; Thu, 07 Nov 2019 12:48:56 -0500 Received: from proxy8.mail.ord1d.rsapps.net ([172.30.191.6]) by director10.mail.ord1d.rsapps.net with LMTP id sPLIEQhZxF0rAwAApN4f7A ; Thu, 07 Nov 2019 12:48:56 -0500 Received: from smtp2.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy8.mail.ord1d.rsapps.net with LMTP id ADCMEQhZxF2FQQAAGdz6CA ; Thu, 07 Nov 2019 12:48:56 -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: smtp2.gate.ord1d.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: de25e732-0186-11ea-b391-5254004a0287-1-1 Received: from [216.105.38.7] ([216.105.38.7:37016] helo=lists.sourceforge.net) by smtp2.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id BF/36-22588-70954CD5; Thu, 07 Nov 2019 12:48:55 -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 1iSlt4-0002IM-Mj; Thu, 07 Nov 2019 17:48:02 +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 1iSlt3-0002Hk-As for openvpn-devel@lists.sourceforge.net; Thu, 07 Nov 2019 17:48:01 +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=tOfvNfM5qnL/WuS/hhfkLZ9Jr6yVUbltjI0ubCqj7RE=; b=hi/K8DSAsmLbZHr3VgdpQhF82b dEZm++vA78fBB7go7NIyy6ceZzD8DPCMysARR8CpR2CNWfvQD1TnCXvWYgeeijoSx4F3ph/Mfzd+u 2T5tN6vwXiYuLwgHMGphGj032FIJPG+x9CBhHgBuAhXAYpl48Me9bZncXN6OV69hi894=; 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=tOfvNfM5qnL/WuS/hhfkLZ9Jr6yVUbltjI0ubCqj7RE=; b=KHFQoJXRxNoeGE7zy/qiPIl0nb LlhobcPHQsFbU6NX+gPkaWHD+FXKKz+6a8Z1PBlt0LZptjSFp2HjR/rdHyv6mgkDWFiJLQWn11VpT PUv0RhJntZ0xBFaXqV0/HOqXibUrcbWiT/Vei8JCedacmwXl9xizq9sbd77DrXK+WWw4=; Received: from mail-wm1-f52.google.com ([209.85.128.52]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.2) id 1iSlsz-003xb7-If for openvpn-devel@lists.sourceforge.net; Thu, 07 Nov 2019 17:48:01 +0000 Received: by mail-wm1-f52.google.com with SMTP id b11so3421932wmb.5 for ; Thu, 07 Nov 2019 09:47:57 -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=tOfvNfM5qnL/WuS/hhfkLZ9Jr6yVUbltjI0ubCqj7RE=; b=vZXMesDefatSIETruX1T8SmB5+A8L85JqPrVHQ8i8MjLP6KBsJgxMKD8tMKZQm75ui r2oh/WDGjUsQpXmH2qv/8bHfOo5JhII56fzhXswnSbhB7cXu0gSqU5qS/JP04VeTVtqv QOODVHTb03c8eKQN/fmgHGdCMQROAWtXAqnLNgh7dulDWtaGFw3H5rUY49EqNDt3eDKu VyXyEhZRE1RZWcai1pcTCCkEBJlxT6UUavBs7335Qg73pCVy0xqK8AldB+UPXdpKTBIa pXk5G+kHEqoob05aTGi7E0H4WlSTvC/lsqMA7C4fl6APntSKc8h6lc75AS44fxLC+4D/ L+pA== 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=tOfvNfM5qnL/WuS/hhfkLZ9Jr6yVUbltjI0ubCqj7RE=; b=GciGXByZcYqE6n2w78ElTODceWSwaGst1m8QE3h6NARa6h5KWTlYeRTDGr5y1TG5Fe um5X5EIlac9R7T0P9sURFZKcxBOdIYLKo1csx+Cx50aBuWNkuRw/d7/IIeK70Z7p0Z7Z Ktfvl90VAIiRnkXWVxL4XVb2biq3kmEMtYCNuPBJYxahGNKPJPyaf7cudwdwYYGyd/9B bMA0ZUsez1cY6RdEv+dWyzxYKJcC1quxlG0XG3kGfm8N47fIDY0ksUO5yFrsyOZd/UAF nQym61EedG+i/H1c1EnjQ1UbmPbXSFwTdsq0aqVpdnR/V4A+QdPT9VO+bAMR8fgvCtX7 uEpg== X-Gm-Message-State: APjAAAWEPtnda61Ow734vm5YnUKqgpZSnfBX7PwELqS8md+KIAMj2YIX z/IGmEmZJsH1n/aVwh7e9Si+jmmhqdew4Q== X-Google-Smtp-Source: APXvYqwAPPH5mJ1JY55s3CzH87Hzt14u0OsfOREe+D/g1kWW2TcZzD5ttpBHcAFFtV1YqslYbzd1tw== X-Received: by 2002:a1c:30b:: with SMTP id 11mr3797860wmd.171.1573148870218; Thu, 07 Nov 2019 09:47:50 -0800 (PST) Received: from stipakov.fi (stipakov.fi. [128.199.52.117]) by smtp.gmail.com with ESMTPSA id l13sm2527752wmh.12.2019.11.07.09.47.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 Nov 2019 09:47:49 -0800 (PST) From: Lev Stipakov To: openvpn-devel@lists.sourceforge.net Date: Thu, 7 Nov 2019 19:45:27 +0200 Message-Id: <1573148729-27339-6-git-send-email-lstipakov@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1573148729-27339-1-git-send-email-lstipakov@gmail.com> References: <1573148729-27339-1-git-send-email-lstipakov@gmail.com> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 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_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.128.52 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (lstipakov[at]gmail.com) -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.128.52 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: 1iSlsz-003xb7-If Subject: [Openvpn-devel] [PATCH v2 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 --- 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 | 54 +++++++++++ src/openvpn/ring_buffer.h | 79 ++++++++++++++++ src/openvpn/tun.c | 89 +++++++++++++++--- src/openvpn/tun.h | 3 + src/openvpn/win32.c | 25 ----- src/openvpn/win32.h | 43 --------- src/openvpnserv/Makefile.am | 3 +- src/openvpnserv/interactive.c | 141 ++++++++++++++++++++++++++-- src/openvpnserv/openvpnserv.vcxproj | 2 + src/openvpnserv/openvpnserv.vcxproj.filters | 6 ++ 14 files changed, 375 insertions(+), 92 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 66177a2..3ed6206 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 a091ffc..d1bb99c 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 9ffef9f..61e634e 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -181,6 +181,7 @@ + @@ -264,6 +265,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index e6068af..8f1b9e0 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -237,6 +237,9 @@ Source Files + + Source Files + @@ -494,10 +497,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 0000000..482e333 --- /dev/null +++ b/src/openvpn/ring_buffer.c @@ -0,0 +1,54 @@ +/* + * 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; + + 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, NULL, 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 0000000..9951cdf --- /dev/null +++ b/src/openvpn/ring_buffer.h @@ -0,0 +1,79 @@ +/* + * 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 + +#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) + +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]; +}; + +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 b909b89..ef1415c 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -799,17 +799,26 @@ init_tun_post(struct tuntap *tt, tt->rw_handle.write = tt->writes.overlapped.hEvent; tt->adapter_index = TUN_ADAPTER_INDEX_INVALID; - tt->send_ring = malloc(sizeof(struct tun_ring)); - tt->receive_ring = malloc(sizeof(struct tun_ring)); - if ((tt->send_ring == NULL) || (tt->receive_ring == NULL)) + if (tt->wintun) { - msg(M_FATAL, "Cannot allocate memory for receive ring"); - } - ZeroMemory(tt->send_ring, sizeof(struct tun_ring)); - ZeroMemory(tt->receive_ring, sizeof(struct tun_ring)); + tt->send_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(struct tun_ring), NULL); + tt->receive_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(struct tun_ring), NULL); + + if ((tt->send_ring_handle == NULL) || (tt->receive_ring_handle == NULL)) + { + msg(M_FATAL, "Cannot allocate memory for ring buffer"); + } + + tt->send_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); + tt->receive_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); - tt->send_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); - tt->receive_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); + if ((tt->send_tail_moved == NULL) || (tt->receive_tail_moved == NULL)) + { + msg(M_FATAL, "Cannot create events for ring buffer"); + } + } #endif } @@ -5628,6 +5637,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->send_ring_handle, + .receive_ring_handle = tt->receive_ring_handle, + .send_tail_moved = tt->send_tail_moved, + .receive_tail_moved = tt->receive_tail_moved + }; + + 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) { @@ -6222,9 +6269,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (tt->wintun) { + tt->send_ring = (struct tun_ring *)MapViewOfFile(tt->send_ring_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); + tt->receive_ring = (struct tun_ring *)MapViewOfFile(tt->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 { @@ -6381,14 +6431,23 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) free(tt->actual_name); } - CloseHandle(tt->receive_tail_moved); CloseHandle(tt->send_tail_moved); + CloseHandle(tt->receive_tail_moved); - free(tt->receive_ring); - free(tt->send_ring); + if (tt->send_ring != NULL) + { + UnmapViewOfFile(tt->send_ring); + tt->send_ring = NULL; + } + + if (tt->receive_ring != NULL) + { + UnmapViewOfFile(tt->receive_ring); + tt->receive_ring = NULL; + } - tt->receive_ring = NULL; - tt->send_ring = NULL; + CloseHandle(tt->send_ring_handle); + CloseHandle(tt->receive_ring_handle); clear_tuntap(tt); free(tt); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index cbdcce4..2799129 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 send_ring_handle; + HANDLE receive_ring_handle; struct tun_ring *send_ring; struct tun_ring *receive_ring; HANDLE send_tail_moved; diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index e9e0258..b2f2a19 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1588,29 +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; - - 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, NULL, NULL); - - return res == TRUE; -} - #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 007c7d7..4b508c5 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -325,50 +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); -#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 bc65070..f8d3319 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 623c3ff..6e72a14 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 7061b7b..c5a34b8 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 3ce9bb2..3cb14ef 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 +