From patchwork Tue Sep 17 02:44:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 825 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director7.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id SHh9JozVgF1HOQAAIUCqbw for ; Tue, 17 Sep 2019 08:46:04 -0400 Received: from proxy12.mail.iad3b.rsapps.net ([172.31.255.6]) by director7.mail.ord1d.rsapps.net with LMTP id YPh5I4zVgF3+SQAAovjBpQ ; Tue, 17 Sep 2019 08:46:04 -0400 Received: from smtp29.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy12.mail.iad3b.rsapps.net with LMTP id 0OujHYzVgF2lTAAAEsW3lA ; Tue, 17 Sep 2019 08:46:04 -0400 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: smtp29.gate.iad3b.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: 1b9cc27c-d949-11e9-9afe-525400534f55-1-1 Received: from [216.105.38.7] ([216.105.38.7:43172] helo=lists.sourceforge.net) by smtp29.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id CF/F4-22157-B85D08D5; Tue, 17 Sep 2019 08:46:03 -0400 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 1iACrN-000381-Fl; Tue, 17 Sep 2019 12:45:33 +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 1iACrL-00037Q-9j for openvpn-devel@lists.sourceforge.net; Tue, 17 Sep 2019 12:45:31 +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:To: From:Sender:Reply-To:Cc: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=cwZlPJtOdxaxgB+hwSMTS/0vv8MGsQB+7YnXd7mzt7E=; b=lq4v+PinHbzWzuqoluf79xJ5of /8td32gx/rQ/K/vf/I5ZTfQxTilNDM7sV811dlsyqa+xArIzCvbhZiGrFGhNypd5f0pm/3zBBUUCy Ya2FLTGuPYbbc/EnlLbYw69Y9rCKLxn8UpehcyB7sGw0k1mLOGhkrqglUpLWUaRPQpwQ=; 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:To:From:Sender:Reply-To:Cc :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=cwZlPJtOdxaxgB+hwSMTS/0vv8MGsQB+7YnXd7mzt7E=; b=PD05CJbZcvBo75xbI9cAPidcU4 zAb9eaQV2315HIK/qB7B8iZK/gE+tRU3+LB97Xvia6FBRrsC6McbKhUfqcyXPSgmuL+okeLCZZ29M oxEpo9PJbwowllfoAsL5NnDk/rHAwQtX/v0aMm0IP8fIARle/zREMlPQsKe/Q6zkX2Do=; Received: from mail-ed1-f66.google.com ([209.85.208.66]) by sfi-mx-4.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.90_1) id 1iACrA-008EyX-3Y for openvpn-devel@lists.sourceforge.net; Tue, 17 Sep 2019 12:45:24 +0000 Received: by mail-ed1-f66.google.com with SMTP id h33so3152633edh.12 for ; Tue, 17 Sep 2019 05:45:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=cwZlPJtOdxaxgB+hwSMTS/0vv8MGsQB+7YnXd7mzt7E=; b=RFjXFbTbHgoRKXKt0+wab/y8fzOZlZQefv0i+B6S8giMEzeIREKpW8FmZl8MBJqEj7 WGJ+XYtJbSortvp2NQ/WHCTcuX9OYKvsuwttmip/gBf2HC72Qb3Ebcxb7t06Fg4JB6Ye dTwFWAEpfeZ9+FjGD6NceifNMcuUzhxrxkLCo0jE5NFsuPFpgOjKf6UspTao7O/UfaYY zPIffpLbCBzQyCEvETzXZSBdXU3GYp0i7M+MHsw0E8Zo8JO4h0PhSPISkijnpvn3W61r BSvgj996M3mRGF8eSSPiTLmXaOQ442wL8t8h2KsZDgiIYWnU9YaJ/Mp5rtuX7+GG7WD5 2YbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=cwZlPJtOdxaxgB+hwSMTS/0vv8MGsQB+7YnXd7mzt7E=; b=dJ5WaP3OPnKmye7ffqXX9ErLlIh/EPobPo+XDKQ4BN5CIMkwnfstKP/pizvNpU3DAt JsemLzsFNAbj34ErSaZ+Am82abcysUhuDUiQUYhKIi9g8BA9/TpV/7sBfyueyqEFLk/V RSmMTEy9+8wjSuAeJBvO9pbdmYMp4Jjis3WCuFTkdXOnt3QJV39GBl1NMLwHcHqAn0Om h2Wmno1obDVGY15PfzNAI+DkyJXGvDH79dEdYp1ayHtk1gh0Aj8LPj3figNDjnpzkeSY x3aYz06fVSgOTQXFBQlFl545XkBAuwc383OQyTwQ/5hezdrCTt7DHkTeGGNPn7v3V0Yn TPgg== X-Gm-Message-State: APjAAAWEWqx16jPPKMqO8GIHQAUf+vBCBcFTp/60V1BQrPaLWmKZl8B3 imgCYpG1evM91vA6qehil/Y+PBVHcM4Kng== X-Google-Smtp-Source: APXvYqxlJy3cZpIr1gBCdG2eBXCBPsNDHPEexDyeHyaHDmU3iJF8XyrwwSMOIBOQ+UO5lhvrF/TXDQ== X-Received: by 2002:a17:906:9451:: with SMTP id z17mr4576119ejx.90.1568724312807; Tue, 17 Sep 2019 05:45:12 -0700 (PDT) Received: from stipakov.fi (stipakov.fi. [128.199.52.117]) by smtp.gmail.com with ESMTPSA id j8sm326585edy.44.2019.09.17.05.45.12 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 17 Sep 2019 05:45:12 -0700 (PDT) From: Lev Stipakov To: openvpn-devel@lists.sourceforge.net Date: Tue, 17 Sep 2019 15:44:50 +0300 Message-Id: <1568724293-5069-4-git-send-email-lstipakov@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1568724293-5069-1-git-send-email-lstipakov@gmail.com> References: <1568724293-5069-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.208.66 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.208.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 0.0 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1iACrA-008EyX-3Y Subject: [Openvpn-devel] [PATCH 4/7] wintun: ring buffers based I/O 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: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Lev Stipakov Implemented according to Wintun documentation and reference client code. Wintun uses ring buffers to communicate between kernel driver and user process. Client allocates send and receive ring buffers, creates events and passes it to kernel driver under LocalSystem privileges. When data is available for read, wintun modifies "tail" pointer of send ring and signals via event. User process reads data from "head" to "tail" and updates "head" pointer. When user process is ready to write, it writes to receive ring, updates "tail" pointer and signals to kernel via event. In openvpn code we add send ring's event to event loop. Before performing io wait, we compare "head" and "tail" pointers of send ring and if they're different, we skip io wait and perform read. This also adds ring buffers support to tcp and udp server code. Signed-off-by: Lev Stipakov --- src/openvpn/forward.c | 44 +++++++++++++++--- src/openvpn/forward.h | 47 +++++++++++++++++++- src/openvpn/mtcp.c | 28 +++++++++++- src/openvpn/mudp.c | 14 ++++++ src/openvpn/options.c | 4 +- src/openvpn/syshead.h | 1 + src/openvpn/tun.c | 45 +++++++++++++++++++ src/openvpn/tun.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++++- src/openvpn/win32.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/win32.h | 47 ++++++++++++++++++++ 10 files changed, 460 insertions(+), 11 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index c2dcb53..7e4ccd3 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1256,12 +1256,32 @@ read_incoming_tun(struct context *c) perf_push(PERF_READ_IN_TUN); c->c2.buf = c->c2.buffers->read_tun_buf; + +#ifdef _WIN32 + if (c->c1.tuntap->wintun) + { + read_wintun(c->c1.tuntap, &c->c2.buf); + if (c->c2.buf.len == -1) + { + register_signal(c, SIGHUP, "tun-abort"); + c->persist.restart_sleep_seconds = 1; + msg(M_INFO, "Wintun read error, restarting"); + perf_pop(); + return; + } + } + else + { +#endif #ifdef TUN_PASS_BUFFER - read_tun_buffered(c->c1.tuntap, &c->c2.buf); + read_tun_buffered(c->c1.tuntap, &c->c2.buf); #else - ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); - ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); - c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame)); + ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); + ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); + c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame)); +#endif +#ifdef _WIN32 + } #endif #ifdef PACKET_TRUNCATION_CHECK @@ -2103,7 +2123,21 @@ io_wait_dowork(struct context *c, const unsigned int flags) * Configure event wait based on socket, tuntap flags. */ socket_set(c->c2.link_socket, c->c2.event_set, socket, (void *)&socket_shift, NULL); - tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)&tun_shift, NULL); + +#ifdef _WIN32 + if (c->c1.tuntap && c->c1.tuntap->wintun) + { + /* add ring buffer event */ + struct rw_handle rw = {.read = c->c1.tuntap->send_tail_moved }; + event_ctl(c->c2.event_set, &rw, EVENT_READ, (void *)&tun_shift); + } + else + { +#endif + tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)&tun_shift, NULL); +#ifdef _WIN32 + } +#endif #ifdef ENABLE_MANAGEMENT if (management) diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 48202c0..6096fa8 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -375,6 +375,19 @@ p2p_iow_flags(const struct context *c) { flags |= IOW_TO_TUN; } +#ifdef _WIN32 + { + struct tuntap *tt = c->c1.tuntap; + if (tt && tt->wintun) + { + if (tt->send_ring->head == tt->send_ring->tail) + { + /* nothing to read from tun -> remove tun read flag set by IOW_READ */ + flags &= ~IOW_READ_TUN; + } + } + } +#endif return flags; } @@ -403,8 +416,38 @@ io_wait(struct context *c, const unsigned int flags) } else { - /* slow path */ - io_wait_dowork(c, flags); +#ifdef _WIN32 + bool skip_iowait = flags & IOW_TO_TUN; + if (flags & IOW_READ_TUN) + { + /* + * don't read from tun if we have pending write to link, + * since every tun read overwrites to_link buffer filled + * by previous tun read + */ + skip_iowait = !(flags & IOW_TO_LINK); + } + if (c->c1.tuntap && c->c1.tuntap->wintun && skip_iowait) + { + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & IOW_READ_TUN) + { + ret |= TUN_READ; + } + c->c2.event_set_status = ret; + } + else + { +#endif + /* slow path */ + io_wait_dowork(c, flags); +#ifdef _WIN32 + } +#endif } } diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index abe2059..9ac51c3 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -270,7 +270,33 @@ multi_tcp_wait(const struct context *c, { int status; socket_set_listen_persistent(c->c2.link_socket, mtcp->es, MTCP_SOCKET); - tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); + +#ifdef _WIN32 + if (c->c1.tuntap && c->c1.tuntap->wintun) + { + if (c->c1.tuntap->send_ring->head != c->c1.tuntap->send_ring->tail) + { + /* there is data in wintun ring buffer, read it immediately */ + mtcp->esr[0].arg = MTCP_TUN; + mtcp->esr[0].rwflags = EVENT_READ; + mtcp->n_esr = 1; + return 1; + } + else + { + /* add ring buffer event */ + struct rw_handle rw = { .read = c->c1.tuntap->send_tail_moved }; + event_ctl(mtcp->es, &rw, EVENT_READ, MTCP_TUN); + } + } + else + { +#endif + tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); +#ifdef _WIN32 + } +#endif + #ifdef ENABLE_MANAGEMENT if (management) { diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index b7f061a..7715063 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -279,6 +279,20 @@ p2mp_iow_flags(const struct multi_context *m) flags |= IOW_READ; } +#ifdef _WIN32 + { + struct tuntap* tt = m->top.c1.tuntap; + if (tt && tt->wintun) + { + if (tt->send_ring->head == tt->send_ring->tail) + { + /* nothing to read from tun -> remove tun read flag set by IOW_READ */ + flags &= ~IOW_READ_TUN; + } + } + } +#endif + return flags; } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9f8e92b..af48e7d 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2939,10 +2939,10 @@ options_postprocess_mutate_invariant(struct options *options) options->ifconfig_noexec = false; } - /* for wintun kernel doesn't send DHCP requests, so use ipapi to set IP address and netmask */ + /* for wintun kernel doesn't send DHCP requests, so use netsh to set IP address and netmask */ if (options->wintun) { - options->tuntap_options.ip_win32_type = IPW32_SET_IPAPI; + options->tuntap_options.ip_win32_type = IPW32_SET_NETSH; } remap_redirect_gateway_flags(options); diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 899aa59..e9accb5 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -39,6 +39,7 @@ #ifdef _WIN32 #include #include +#include #define sleep(x) Sleep((x)*1000) #define random rand #define srandom srand diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 5415dbb..ebbfbb5 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -798,6 +798,18 @@ init_tun_post(struct tuntap *tt, tt->rw_handle.read = tt->reads.overlapped.hEvent; 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)) + { + 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_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); + tt->receive_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); #endif } @@ -6197,6 +6209,30 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun tt->ipapi_context_defined = true; } } + + if (tt->wintun) + { + if (tt->options.msg_channel) + { + /* TODO */ + } + 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->send_ring, tt->receive_ring, tt->send_tail_moved, tt->receive_tail_moved)) + { + msg(M_FATAL, "ERROR: Failed to register ring buffers: %lu", GetLastError()); + } + if (!RevertToSelf()) + { + msg(M_FATAL, "ERROR: RevertToSelf error: %lu", GetLastError()); + } + } + } + /*netcmd_semaphore_release ();*/ gc_free(&gc); } @@ -6335,6 +6371,15 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) free(tt->actual_name); } + CloseHandle(tt->receive_tail_moved); + CloseHandle(tt->send_tail_moved); + + free(tt->receive_ring); + free(tt->send_ring); + + tt->receive_ring = NULL; + tt->send_ring = NULL; + clear_tuntap(tt); free(tt); gc_free(&gc); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 18eb1b0..5b15dc9 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -183,6 +183,11 @@ struct tuntap bool wintun; /* true if wintun is used instead of tap-windows6 */ int standby_iter; + + struct tun_ring *send_ring; + struct tun_ring *receive_ring; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; #else /* ifdef _WIN32 */ int fd; /* file descriptor for TUN/TAP dev */ #endif @@ -481,10 +486,124 @@ read_tun_buffered(struct tuntap *tt, struct buffer *buf) return tun_finalize(tt->hand, &tt->reads, buf); } +static inline ULONG +wintun_ring_packet_align(ULONG size) +{ + return (size + (WINTUN_PACKET_ALIGN - 1)) & ~(WINTUN_PACKET_ALIGN - 1); +} + +static inline ULONG +wintun_ring_wrap(ULONG value) +{ + return value & (WINTUN_RING_CAPACITY - 1); +} + +static inline void +read_wintun(struct tuntap *tt, struct buffer* buf) +{ + struct tun_ring *ring = tt->send_ring; + ULONG head = ring->head; + ULONG tail = ring->tail; + ULONG content_len; + struct TUN_PACKET *packet; + ULONG aligned_packet_size; + + *buf = tt->reads.buf_init; + buf->len = 0; + + if ((head >= WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY)) + { + msg(M_INFO, "Wintun: ring capacity exceeded"); + buf->len = -1; + return; + } + + if (head == tail) + { + /* nothing to read */ + return; + } + + content_len = wintun_ring_wrap(tail - head); + if (content_len < sizeof(struct TUN_PACKET_HEADER)) + { + msg(M_INFO, "Wintun: incomplete packet header in send ring"); + buf->len = -1; + return; + } + + packet = (struct TUN_PACKET *) &ring->data[head]; + if (packet->size > WINTUN_MAX_PACKET_SIZE) + { + msg(M_INFO, "Wintun: packet too big in send ring"); + buf->len = -1; + return; + } + + aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + packet->size); + if (aligned_packet_size > content_len) + { + msg(M_INFO, "Wintun: incomplete packet in send ring"); + buf->len = -1; + return; + } + + buf_write(buf, packet->data, packet->size); + + head = wintun_ring_wrap(head + aligned_packet_size); + ring->head = head; +} + +static inline int +write_wintun(struct tuntap *tt, struct buffer *buf) +{ + struct tun_ring *ring = tt->receive_ring; + ULONG head = ring->head; + ULONG tail = ring->tail; + ULONG aligned_packet_size; + ULONG buf_space; + struct TUN_PACKET *packet; + + if ((head > WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY)) + { + msg(M_INFO, "Wintun: head/tail value is over capacity"); + return -1; + } + + aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + BLEN(buf)); + buf_space = wintun_ring_wrap(head - tail - WINTUN_PACKET_ALIGN); + if (aligned_packet_size > buf_space) + { + msg(M_INFO, "Wintun: ring is full"); + return 0; + } + + /* copy packet size and data into ring */ + packet = (struct TUN_PACKET* )&ring->data[tail]; + packet->size = BLEN(buf); + memcpy(packet->data, BPTR(buf), BLEN(buf)); + + /* move ring tail */ + ring->tail = wintun_ring_wrap(tail + aligned_packet_size); + if (ring->alertable != 0) + { + SetEvent(tt->receive_tail_moved); + } + + return BLEN(buf); +} + static inline int write_tun_buffered(struct tuntap *tt, struct buffer *buf) { - return tun_write_win32(tt, buf); + if (tt->wintun) + { + return write_wintun(tt, buf); + } + else + { + return tun_write_win32(tt, buf); + } } #else /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index eb4c030..e9e0258 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1493,4 +1493,124 @@ send_msg_iservice(HANDLE pipe, const void *data, size_t size, return ret; } +bool +impersonate_as_system() +{ + HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token; + PROCESSENTRY32 entry; + BOOL ret; + DWORD pid = 0; + TOKEN_PRIVILEGES privileges; + + CLEAR(entry); + CLEAR(privileges); + + entry.dwSize = sizeof(PROCESSENTRY32); + + privileges.PrivilegeCount = 1; + privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED; + + if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid)) + { + return false; + } + + if (!ImpersonateSelf(SecurityImpersonation)) + { + return false; + } + + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token)) + { + RevertToSelf(); + return false; + } + if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL)) + { + CloseHandle(thread_token); + RevertToSelf(); + return false; + } + CloseHandle(thread_token); + + process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (process_snapshot == INVALID_HANDLE_VALUE) + { + RevertToSelf(); + return false; + } + for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry)) + { + if (!_stricmp(entry.szExeFile, "winlogon.exe")) + { + pid = entry.th32ProcessID; + break; + } + } + CloseHandle(process_snapshot); + if (!pid) + { + RevertToSelf(); + return false; + } + + winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!winlogon_process) + { + RevertToSelf(); + return false; + } + + if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token)) + { + CloseHandle(winlogon_process); + RevertToSelf(); + return false; + } + CloseHandle(winlogon_process); + + if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token)) + { + CloseHandle(winlogon_token); + RevertToSelf(); + return false; + } + CloseHandle(winlogon_token); + + if (!SetThreadToken(NULL, duplicated_token)) + { + CloseHandle(duplicated_token); + RevertToSelf(); + return false; + } + CloseHandle(duplicated_token); + + 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 4814bbc..007c7d7 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -25,6 +25,8 @@ #ifndef OPENVPN_WIN32_H #define OPENVPN_WIN32_H +#include + #include "mtu.h" #include "openvpn-msg.h" #include "argv.h" @@ -323,5 +325,50 @@ 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 */