From patchwork Tue Dec 7 01:11:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2111 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director10.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id cHeUONJPr2EaLgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:06 -0500 Received: from proxy16.mail.ord1d.rsapps.net ([172.30.191.6]) by director10.mail.ord1d.rsapps.net with LMTP id eHhxDNNPr2GeaAAApN4f7A (envelope-from ) for ; Tue, 07 Dec 2021 07:13:07 -0500 Received: from smtp13.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy16.mail.ord1d.rsapps.net with LMTPS id KL4wDNNPr2F8CAAAetu3IA (envelope-from ) for ; Tue, 07 Dec 2021 07:13:07 -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: smtp13.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 08e7670c-5757-11ec-b513-bc305bf03494-1-1 Received: from [216.105.38.7] ([216.105.38.7:43824] helo=lists.sourceforge.net) by smtp13.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id E9/94-21545-2DF4FA16; Tue, 07 Dec 2021 07:13:07 -0500 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1muZKM-0004og-Ej; Tue, 07 Dec 2021 12:12:11 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKK-0004oO-VN for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:10 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=miXVpF2gJWo6yRr7Eqlqo0NLQP6r4vY2lKeAb9c8obs=; b=cf9wNvk6XyyZriBbol2bTRPApP wsleAXJGv96gQt0Kw5F3YWg2mC2g1J+YOmam2zMYJow8oMCHq9bDeuMyg6zHRMz5EimE6kUnmDpd/ W+sDcAFWKqmvnNiTSUGuBLDvmjmNHwfylOqjct/UwRcjghVubkVxylOeAi2zVqxScItg=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=miXVpF2gJWo6yRr7Eqlqo0NLQP6r4vY2lKeAb9c8obs=; b=DMzuM18yiank+Th2ruulOuRx1s 2S9r1Dvj9/GIK+RSVijdkvQfr3zmGVg78moqYCYOJcObR+B6Smp+JUIz8L5+G2eaZh8qRo3HJNK15 LcBWtc0FuQ9uGgtZkcYEzHOjY2wnIoGn5x8dazmVTGSJWrKv9Ji68CJkLTYyI34uQ2qA=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKH-007MQN-6j for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:09 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:30 +0100 Message-Id: <20211207121137.3221-2-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Arne Schwabe The net_ctx_init/reset/free methods of sitnl are the same dummy methods that are already defined for non-Linux platforms in the networking.h header. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- src/openvpn/networking.h | 7 ++++++- src/openvpn/networking_sitnl.c | 22 2 fi [...] Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKH-007MQN-6j Subject: [Openvpn-devel] [RFC 1/8] networking: remove duplicate methods from networking_sitnl.c 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: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Arne Schwabe The net_ctx_init/reset/free methods of sitnl are the same dummy methods that are already defined for non-Linux platforms in the networking.h header. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- src/openvpn/networking.h | 7 ++++++- src/openvpn/networking_sitnl.c | 22 ---------------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/src/openvpn/networking.h b/src/openvpn/networking.h index d43979f0..ad25fc79 100644 --- a/src/openvpn/networking.h +++ b/src/openvpn/networking.h @@ -33,7 +33,12 @@ struct context; /* define mock types to ensure code builds on any platform */ typedef void *openvpn_net_ctx_t; typedef void *openvpn_net_iface_t; +#endif /* ifdef ENABLE_SITNL */ +/* Only the iproute2 backend implements these functions, + * the rest can rely on these stubs + */ +#if !defined(ENABLE_IPROUTE) static inline int net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx) { @@ -51,7 +56,7 @@ net_ctx_free(openvpn_net_ctx_t *ctx) { (void)ctx; } -#endif /* ifdef ENABLE_SITNL */ +#endif /* !defined(ENABLE_IPROUTE) */ #if defined(ENABLE_SITNL) || defined(ENABLE_IPROUTE) diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c index 8610e1d2..e0003f5c 100644 --- a/src/openvpn/networking_sitnl.c +++ b/src/openvpn/networking_sitnl.c @@ -595,28 +595,6 @@ net_route_v6_best_gw(openvpn_net_ctx_t *ctx, const struct in6_addr *dst, } #ifdef ENABLE_SITNL - -int -net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx) -{ - (void)c; - (void)ctx; - - return 0; -} - -void -net_ctx_reset(openvpn_net_ctx_t *ctx) -{ - (void)ctx; -} - -void -net_ctx_free(openvpn_net_ctx_t *ctx) -{ - (void)ctx; -} - int net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst, in_addr_t *best_gw, char *best_iface) From patchwork Tue Dec 7 01:11:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2112 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director10.mail.ord1d.rsapps.net ([172.27.255.56]) by backend41.mail.ord1d.rsapps.net with LMTP id IglfOtRPr2EmLgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:08 -0500 Received: from proxy3.mail.iad3a.rsapps.net ([172.27.255.56]) by director10.mail.ord1d.rsapps.net with LMTP id WCxBDdVPr2EsaAAApN4f7A (envelope-from ) for ; Tue, 07 Dec 2021 07:13:09 -0500 Received: from smtp49.gate.iad3a ([172.27.255.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy3.mail.iad3a.rsapps.net with LMTPS id qEWxBtVPr2E5XwAAYaqY3Q (envelope-from ) for ; Tue, 07 Dec 2021 07:13:09 -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: smtp49.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 09efe6a6-5757-11ec-a8a2-525400fffce0-1-1 Received: from [216.105.38.7] ([216.105.38.7:53734] helo=lists.sourceforge.net) by smtp49.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 25/B0-11802-4DF4FA16; Tue, 07 Dec 2021 07:13:08 -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.94.2) (envelope-from ) id 1muZKO-00009F-G9; Tue, 07 Dec 2021 12:12:12 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKN-000090-0j for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=8iXpgx3J+qc57cjFkUfG1fH1C2n/mS6hfvgwqyCiTj0=; b=fAgqtmkcAwb9kqIR7OJt1doU8R sJE4U2MCxpCkVlCjDgwkV6TpqSrnr92f1Sa6WwDo4lxYnTcf8gZO7sedVR+d54uZyw6nnWpENNM0g KdX3i8NCDSP2MmXqY9MPfrU2++KkPkGAMd5gPfs8pKnny/0SdUUUUiZJi8+rOCwBV0Bw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=8iXpgx3J+qc57cjFkUfG1fH1C2n/mS6hfvgwqyCiTj0=; b=eu0ajVN9LzDgFhHsUOEKmPgEqE pDw0HtvBkzWAbP5hzQ5/kDm98rbnYD7scqZ/h4u1x2m8qKciWuxW1bMZUE1nmN59TjYJRAa5LW2tj l1XaNmLTQ6+mnfKTMd8fa/2CYqDG/YE0bf8meRgnHZVmOVS6+IkMGOo2TxMYsnnrrrhQ=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKI-0008Ol-Tj for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:10 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:31 +0100 Message-Id: <20211207121137.3221-3-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: In the net_ctx_init() stub definition, arguments are not used and therefore they should be explicitly marked to avoid compiler warnings. Signed-off-by: Antonio Quartulli --- src/openvpn/networking.h | 3 +++ 1 file changed, 3 insertions(+) Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKI-0008Ol-Tj Subject: [Openvpn-devel] [RFC 2/8] networking: silence warnings about unused arguments 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: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox In the net_ctx_init() stub definition, arguments are not used and therefore they should be explicitly marked to avoid compiler warnings. Signed-off-by: Antonio Quartulli --- src/openvpn/networking.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/openvpn/networking.h b/src/openvpn/networking.h index ad25fc79..2f0ee160 100644 --- a/src/openvpn/networking.h +++ b/src/openvpn/networking.h @@ -42,6 +42,9 @@ typedef void *openvpn_net_iface_t; static inline int net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx) { + (void)c; + (void)ctx; + return 0; } From patchwork Tue Dec 7 01:11:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2113 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id 8AK8HtVPr2EmLgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:09 -0500 Received: from proxy9.mail.ord1d.rsapps.net ([172.30.191.6]) by director12.mail.ord1d.rsapps.net with LMTP id 8NUmBNVPr2HdUAAAIasKDg (envelope-from ) for ; Tue, 07 Dec 2021 07:13:09 -0500 Received: from smtp24.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy9.mail.ord1d.rsapps.net with LMTPS id QKYOLtVPr2H1WAAA7h+8OQ (envelope-from ) for ; Tue, 07 Dec 2021 07:13:09 -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: smtp24.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 09ebcad0-5757-11ec-aab2-b8ca3a674470-1-1 Received: from [216.105.38.7] ([216.105.38.7:34254] helo=lists.sourceforge.net) by smtp24.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 5B/84-36340-4DF4FA16; Tue, 07 Dec 2021 07:13:08 -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.94.2) (envelope-from ) id 1muZKU-0002w4-P7; Tue, 07 Dec 2021 12:12:18 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKN-0002vh-8A for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=6tl45DPnRguNb7CtOOr3MAJ3eFOVpDqbiMKuiq8hzLs=; b=Jey3mesVouOjg15hKv5sSyXaCP N0DCtbG8S3gtk2UOf67BUVW0xgIY2yjMtdH3PpH2e7boOFTIXbXvPMN2GCTMn9Jjt2+9UAzfcleZd Xh56p0zKakBD3BNNC4bylvoxC3bzR++vyRgdMVL0KVGsENSVYl6TqDkJVZbv2iEXWymI=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=6tl45DPnRguNb7CtOOr3MAJ3eFOVpDqbiMKuiq8hzLs=; b=Fs7YvtXaCTQb4t8zQxXucCkb8Z EThhOI//Ua3LvR3hpdRywpinzXiPTfPP//cp0as4vC7sm36DGX71UN/JLPE/PKBUnLYI9BORRv5HB F2pNSuH6n3Vy6tYVWqbhJpLdEeZLJPAN6aWEoEIrmLYa1w6m8e7uQQ29KiHU04Kr/zvk=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKJ-0008P4-1n for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:11 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:32 +0100 Message-Id: <20211207121137.3221-4-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Arne Schwabe These two new methods can be used to create and delete a tun or an ovpn-dco interface via RTNL API. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- src/openvpn/networking_sitnl.c | 94 ++++++++++++++++++++++ src/openvpn/networking_sitnl.h | 28 +++++ [...] Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKJ-0008P4-1n Subject: [Openvpn-devel] [RFC 3/8] sitnl: implement net_iface_new and net_iface_del 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: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Arne Schwabe These two new methods can be used to create and delete a tun or an ovpn-dco interface via RTNL API. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- src/openvpn/networking_sitnl.c | 94 ++++++++++++++++++++++ src/openvpn/networking_sitnl.h | 28 +++++++ tests/unit_tests/openvpn/test_networking.c | 22 ++++- 3 files changed, 143 insertions(+), 1 deletion(-) diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c index e0003f5c..e6ffdb64 100644 --- a/src/openvpn/networking_sitnl.c +++ b/src/openvpn/networking_sitnl.c @@ -1312,6 +1312,100 @@ net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst, table, metric); } + +int +net_iface_new(const char *iface, const char *type) +{ + struct sitnl_link_req req = { }; + struct rtattr *tail = NULL; + int ret = -1; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL ; + req.n.nlmsg_type = RTM_NEWLINK; + + if (iface) + { + SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface, strlen(iface) + 1); + } + tail = NLMSG_TAIL(&req.n); + SITNL_ADDATTR(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + SITNL_ADDATTR(&req.n, sizeof(req), IFLA_INFO_KIND, type, + strlen(type) + 1); + tail->rta_len = (uint8_t *)NLMSG_TAIL(&req.n) - (uint8_t *)tail; + + req.i.ifi_family = AF_PACKET; + req.i.ifi_change = 0xFFFFFFFF; + + msg(D_ROUTE, "%s: add %s type %s", __func__, np(iface), type); + + if (iface) + { + /* if we have an interface name we can use that name to later + * lookup what interface index we created */ + ret = sitnl_send(&req.n, 0, 0, NULL, NULL); + if (!ret) + { + req.i.ifi_index = if_nametoindex(iface); + } + + } + else + { + req.i.ifi_index = 1194; + do + { + /* for some reason RTM_NEWLINK does not have a reply */ + /* Therefore we use try using different if indices untiles + * we get one that does not exist already */ + req.i.ifi_index++; + ret = sitnl_send(&req.n, 0, 0, NULL, NULL); + } + while (ret == -EEXIST); + } + if (!ret) + { + return req.i.ifi_index; + } + +err: + return ret; +} + +int +net_iface_del_name(const char *iface) +{ + int ifindex; + + ifindex = if_nametoindex(iface); + + msg(D_ROUTE,"%s: idel %s", __func__, iface); + + if (ifindex == 0) + { + msg(D_ROUTE|M_ERRNO, "%s: rtnl: cannot get ifindex for %s:", + __func__, iface); + return -ENOENT; + } + + return net_iface_del_index(ifindex); +} + +int +net_iface_del_index(int ifindex) +{ + struct sitnl_link_req req = { }; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELLINK; + + req.i.ifi_family = AF_PACKET; + req.i.ifi_index = ifindex; + + return sitnl_send(&req.n, 0, 0, NULL, NULL); +} + #endif /* !ENABLE_SITNL */ #endif /* TARGET_LINUX */ diff --git a/src/openvpn/networking_sitnl.h b/src/openvpn/networking_sitnl.h index f040020e..b88ffd4b 100644 --- a/src/openvpn/networking_sitnl.h +++ b/src/openvpn/networking_sitnl.h @@ -25,4 +25,32 @@ typedef char openvpn_net_iface_t; typedef void *openvpn_net_ctx_t; +/** + * @brief Add new interface (similar to ip link add) + * + * @param iface interface name + * @param type interface link type (for example "ovpn-dco") + * @return int 0 on success, negative error code on error + */ +int +net_iface_new(const char *iface, const char *type); + +/** + * @brief Remove an interface (similar to ip link remove) + * + * @param iface interface name + * @return int 0 on success, negative error code on error + */ +int +net_iface_del_name(const char *iface); + +/** + * @brief Remove an interface (similar to ip link remove) + * + * @param ifindex interface index + * @return int 0 on success, negative error code on error + */ +int +net_iface_del_index(int ifindex); + #endif /* NETWORKING_SITNL_H_ */ diff --git a/tests/unit_tests/openvpn/test_networking.c b/tests/unit_tests/openvpn/test_networking.c index 9e9744f4..37b97188 100644 --- a/tests/unit_tests/openvpn/test_networking.c +++ b/tests/unit_tests/openvpn/test_networking.c @@ -13,6 +13,20 @@ net__iface_up(bool up) return net_iface_up(NULL, iface, up); } +static int +net__iface_new(const char *name, const char* type) +{ + printf("CMD: ip link add %s type %s\n", name, type); + return net_iface_new(name, type); +} + +static int +net__iface_del(const char *name) +{ + printf("CMD: ip link del %s\n", name); + return net_iface_del_name(name); +} + static int net__iface_mtu_set(int mtu) { @@ -191,7 +205,7 @@ net__route_v6_add_gw(const char *dst_str, int prefixlen, const char *gw_str, static void usage(char *name) { - printf("Usage: %s <0-7>\n", name); + printf("Usage: %s <0-9>\n", name); } int @@ -243,6 +257,12 @@ main(int argc, char *argv[]) case 7: return net__route_v6_add_gw("2001:cafe:babe::", 48, "2001::2", 600); + case 8: + return net__iface_new("dummy0815", "dummy"); + + case 9: + return net__iface_del("dummy0815"); + default: printf("invalid test: %d\n", test); break; From patchwork Tue Dec 7 01:11:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2119 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.27.255.52]) by backend41.mail.ord1d.rsapps.net with LMTP id qEFXI+BPr2FELgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:20 -0500 Received: from proxy16.mail.iad3a.rsapps.net ([172.27.255.52]) by director11.mail.ord1d.rsapps.net with LMTP id IJ/5MuBPr2F2awAAvGGmqA (envelope-from ) for ; Tue, 07 Dec 2021 07:13:20 -0500 Received: from smtp21.gate.iad3a ([172.27.255.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy16.mail.iad3a.rsapps.net with LMTPS id MN4fLOBPr2FWGwAADc5QwQ (envelope-from ) for ; Tue, 07 Dec 2021 07:13:20 -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: smtp21.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 10736818-5757-11ec-96e8-525400e75841-1-1 Received: from [216.105.38.7] ([216.105.38.7:33068] helo=lists.sourceforge.net) by smtp21.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 09/32-23455-FDF4FA16; Tue, 07 Dec 2021 07:13:20 -0500 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1muZKV-0004qA-Po; Tue, 07 Dec 2021 12:12:20 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKS-0004p7-EJ for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:17 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=FL68yQ8Kt/wGTfv6yy/qm7XWBCwmUjLy+LuVyUYMtnw=; b=jlr5ur6u46HSjOCBDYw6u9Paek uSDfhaDE1+8XRWVGsVB+rDc7QaSQwBgHPjImjIXE8TUGCC4Eyfz0PU8YhX5K/Dz3y8a19ypLfP8/9 LLTC3ycTSXBP+QqrjcU534qGWXOPAMMWKaiDKQqtBrM5VnbVAdeAbwkYJID+YxFIdvv8=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=FL68yQ8Kt/wGTfv6yy/qm7XWBCwmUjLy+LuVyUYMtnw=; b=eEIDm4Y4Lu6n1buErKjLlTD9Dw 1Dnk2/GwzmU0I3Mei1E2GaLkmIae6d7P04pe5lPC60/fJbqVCjNXYFor9QdgT1qfVVNr/FoUztMEm 2d4n636jjwArwwnWBF8guqM23cd8sSq7ezz51FN4/39HbuRCDeCQ9TQEuccZVp7icfzc=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKI-0008P3-LK for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:13 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:33 +0100 Message-Id: <20211207121137.3221-5-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Arne Schwabe Implement the data-channel offloading using the ovpn-dco kernel module. See README.dco.md for more details. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- Changes.rst | 7 + README.dco.md | 124 +++ configure.ac | 56 ++ doc/man-sections/advanced-options.rst [...] Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKI-0008P3-LK Subject: [Openvpn-devel] [RFC 4/8] ovpn-dco: introduce linux data-channel offload 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: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Arne Schwabe Implement the data-channel offloading using the ovpn-dco kernel module. See README.dco.md for more details. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- Changes.rst | 7 + README.dco.md | 124 +++ configure.ac | 56 ++ doc/man-sections/advanced-options.rst | 13 + src/openvpn/Makefile.am | 8 +- src/openvpn/crypto.c | 10 + src/openvpn/crypto.h | 6 + src/openvpn/dco.c | 272 +++++++ src/openvpn/dco.h | 118 +++ src/openvpn/errlevel.h | 2 + src/openvpn/event.h | 3 + src/openvpn/forward.c | 66 +- src/openvpn/init.c | 153 +++- src/openvpn/init.h | 2 +- src/openvpn/mtcp.c | 61 +- src/openvpn/mudp.c | 13 + src/openvpn/multi.c | 278 ++++++- src/openvpn/multi.h | 6 +- src/openvpn/networking.h | 1 + src/openvpn/networking_linuxdco.c | 848 +++++++++++++++++++++ src/openvpn/networking_linuxdco.h | 85 +++ src/openvpn/openvpn.vcxproj | 4 +- src/openvpn/openvpn.vcxproj.filters | 6 + src/openvpn/options.c | 143 +++- src/openvpn/options.h | 26 + src/openvpn/socket.h | 1 + src/openvpn/ssl.c | 6 +- src/openvpn/ssl_common.h | 13 + src/openvpn/ssl_ncp.c | 2 +- src/openvpn/tun.c | 13 +- src/openvpn/tun.h | 4 + tests/unit_tests/openvpn/test_networking.c | 9 +- 32 files changed, 2305 insertions(+), 54 deletions(-) create mode 100644 README.dco.md create mode 100644 src/openvpn/dco.c create mode 100644 src/openvpn/dco.h create mode 100644 src/openvpn/networking_linuxdco.c create mode 100644 src/openvpn/networking_linuxdco.h diff --git a/Changes.rst b/Changes.rst index b7d7f205..b613d656 100644 --- a/Changes.rst +++ b/Changes.rst @@ -62,6 +62,13 @@ Optional ciphers in ``--data-ciphers`` Ciphers in ``--data-ciphers`` can now be prefixed with a ``?`` to mark those as optional and only use them if the SSL library supports them. +Data channel offloading with ovpn-dco + 2.6.0+ implements support for data-channel offloading where the data packets + are directly processed and forwarded in kernel space thanks to the ovpn-dco + kernel module. The userspace openvpn program acts purely as a control plane + application. + + Deprecated features ------------------- ``inetd`` has been removed diff --git a/README.dco.md b/README.dco.md new file mode 100644 index 00000000..e2500d36 --- /dev/null +++ b/README.dco.md @@ -0,0 +1,124 @@ +OpenVPN data channel offload +============================ +2.6.0+ implements support for data-channel offloading where the data packets +are directly processed and forwarded in kernel space thanks to the ovpn-dco +kernel module. The userspace openvpn program acts purely as a control plane +application. + +Overview of current release +--------------------------- +- See the "Limitations by design" and "Current limitations" sections for + features that are not and/or will not be supported by OpenVPN + ovpn-dco +- The dco branch is based on my working branch and contains a number of + other patch sets that are not yet merged into the OpenVPN master branch + (e.g. --peer-fingerprint). + + +Getting started (Linux) +----------------------- + +- Use a recent Linux kernel. Ubuntu 20.04 (Linux 5.4.0) and Ubuntu 20.10 + (Linux 5.8.0) are known to work with ovpn-dco. + +Get the ovpn-dco module from one these urls and build it: + +* https://gitlab.com/openvpn/ovpn-dco +* https://github.com/OpenVPN/ovpn-dco + +e.g. + + git clone https://github.com/OpenVPN/ovpn-dco + cd ovpn-dco + make + sudo make install + +If you want to report bugs please ensure to compile ovpn-dco with +`make DEBUG=1` and include any debug message being printed by the +kernel (you can view those messages with `dmesg`). + +Clone OpenVPN and build dco branch. For example: + + git clone -b dco https://github.com/schwabe/openvpn.git + cd openvpn + autoreconf -vi + ./configure --enable-dco + make + make install # Or run just src/openvpn/openvpn + +If you start openvpn it should automatically detect DCO support and use the +kernel module. Add the option `--disable-dco` to disable data channel offload +support. If the configuration contains an option that is incompatible with +data channel offloading OpenVPN will automatically disable DCO support and +warn the user. + +Should OpenVPN be configured to use a feature that is not supported by ovpn-dco +or should the ovpn-dco kernel module not be available on the system, you will +see a message like + + Note: Kernel support for ovpn-dco missing, disabling data channel offload. + +in your log. + + +DCO and P2P mode +---------------- +DCO is also available when running OpenVPN in P2P mode without --pull/--client option. +The P2P mode is useful for scenarios when the OpenVPN tunnel should not interfere with +overall routing and behave more like a "dumb" tunnel like GRE. + +However, DCO requires DATA_V2 to be enabled this requires P2P with NCP capability, which +is only available in OpenVPN 2.6 and later. + +OpenVPN prints a diagnostic message for the P2P NCP result when running in P2P mode: + + P2P mode NCP negotiation result: TLS_export=1, DATA_v2=1, peer-id 9484735, cipher=AES-256-GCM + +Double check that your have `DATA_v2=1` in your output and a supported AEAD cipher +(AES-GCM or Chacha20-Poly1305). + +Routing with ovpn-dco +--------------------- +The ovpn-dco kernel module implements a more transparent approach to +configuring routes to clients (aka 'iroutes') and consults the kernel +routing tables for forwarding decisions. + +- Each client has an IPv4 VPN IP and/or an IPv6 assigned to it +- Additional IP ranges can be routed to a client by adding a route with + a client VPN IP as the gateway/nexthop. +- No internal routing (iroutes) is available. If you need truly internal + routes, this can be achieved either with filtering using `iptables` or + using `ip rule`. + + +Limitations by design +---------------------- +- Layer 3 (dev tun only) +- only AEAD ciphers are supported and currently only + Chacha20-Poly1305 and AES-GCM-128/192/256 +- no support for compression or compression framing + - see also `--compress migrate` option to move to a setup with compression +- various features not implemented since have better replacements + - --shaper, use tc instead + - packet manipulation, use nftables/iptables instead +- OpenVPN 2.4.0 is the minimum peer version. + - older version are missing support for the AEAD ciphers +- topology subnet is the only supported `--topology` for servers +- iroute directives install routes on the host operating system, see also + routing with ovpn-dco + +Current limitations +------------------- +- --persistent-tun not tested/supported +- fallback to non-dco in client mode missing +- IPv6 mapped IPv4 addresses need Linux 5.12 to properly work +- Some incompatible options may not properly fallback to non-dco +- TCP performance with ovpn-dco can still exhibit bad behaviour and drop to a + few megabits per seconds. +- Not all options that should trigger disabling DCO as they are incompatible + are currently identified. Some options that do not trigger disabling DCO + are ignored while other might yield unexpected results. +- ovpn-dco currently does not implement RPF checks and will accept any source + IP from any client. +- If a peer VPN IP is outside the default device subnet, the route needs to be + added manually. +- No per client statistics. Only total statistics available on the interface. diff --git a/configure.ac b/configure.ac index e0f9c332..7d05d905 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,13 @@ AC_ARG_ENABLE( [enable_small="no"] ) +AC_ARG_ENABLE( + [dco], + [AS_HELP_STRING([--enable-dco], [enable data channel offload support using ovpn-dco kernel module @<:@default=no@:>@])], + , + [enable_dco="no"] +) + AC_ARG_ENABLE( [iproute2], [AS_HELP_STRING([--enable-iproute2], [enable support for iproute2 @<:@default=no@:>@])], @@ -766,6 +773,53 @@ PKG_CHECK_MODULES( [] ) + + +if test "$enable_dco" = "yes"; then +dnl +dnl Configure path for the ovpn-dco kernel module source directory. +dnl +dnl This is similar to the core librariy, there is an embedded +dnl version in this tree which will be used by default. The +dnl git checkout inside the ovpn-dco/ directory is managed via git +dnl submodule. +dnl +AC_ARG_VAR([DCO_SOURCEDIR], [Alternative ovpn-dco kernel module source directory]) +if test -z "${DCO_SOURCEDIR}"; then + DCO_SOURCEDIR="${srcdir}/../ovpn-dco" +fi +AC_MSG_NOTICE([Using ovpn-dco source directory: ${DCO_SOURCEDIR}]) +AC_SUBST([DCO_SOURCEDIR]) + +dnl +dnl Include generic netlink library used to talk to ovpn-dco +dnl + saved_CFLAGS="${CFLAGS}" + PKG_CHECK_MODULES( + [LIBNL_GENL], + [libnl-genl-3.0 >= 3.2.29], + [have_libnl="yes"], + [AC_MSG_ERROR([libnl-genl-3.0 package not found or too old. Is the development package and pkg-config installed? Must be version 3.4.0 or newer])] + ) + + DCO_CFLAGS="-I${DCO_SOURCEDIR}/include/uapi ${LIBNL_GENL_CFLAGS}" + + CFLAGS="${CFLAGS} ${DCO_CFLAGS}" + AC_CHECK_HEADERS( + [linux/ovpn_dco.h], + , + [AC_MSG_ERROR([linux/ovpn_dco.h is missing (use DCO_SOURCE to set path to it, CFLAGS=${CFLAGS})])] + ) + CFLAGS=${saved_CFLAGS} + OPTIONAL_DCO_CFLAGS="${DCO_CFLAGS}" + OPTIONAL_DCO_LIBS="${LIBNL_GENL_LIBS}" + + AC_DEFINE(ENABLE_LINUXDCO, 1, [Enable linux data channel offload]) + AC_DEFINE(ENABLE_DCO, 1, [Enable shared data channel offload]) +fi +AM_CONDITIONAL([ENABLE_OVPNDCO], [test "${enable_dco}" = "yes"]) + + if test "${with_crypto_library}" = "openssl"; then AC_ARG_VAR([OPENSSL_CFLAGS], [C compiler flags for OpenSSL]) AC_ARG_VAR([OPENSSL_LIBS], [linker flags for OpenSSL]) @@ -1331,6 +1385,8 @@ AC_SUBST([OPTIONAL_PKCS11_HELPER_CFLAGS]) AC_SUBST([OPTIONAL_PKCS11_HELPER_LIBS]) AC_SUBST([OPTIONAL_INOTIFY_CFLAGS]) AC_SUBST([OPTIONAL_INOTIFY_LIBS]) +AC_SUBST([OPTIONAL_DCO_CFLAGS]) +AC_SUBST([OPTIONAL_DCO_LIBS]) AC_SUBST([PLUGIN_AUTH_PAM_CFLAGS]) AC_SUBST([PLUGIN_AUTH_PAM_LIBS]) diff --git a/doc/man-sections/advanced-options.rst b/doc/man-sections/advanced-options.rst index 5157c561..cdec9502 100644 --- a/doc/man-sections/advanced-options.rst +++ b/doc/man-sections/advanced-options.rst @@ -91,3 +91,16 @@ used when debugging or testing out special usage scenarios. *(Linux only)* Set the TX queue length on the TUN/TAP interface. Currently defaults to operating system default. +--disable-dco + Disables the opportunistic use the data channel offloading if available. + Without this option, OpenVPN will opportunistically use DCO mode if + the config options and the running kernel supports using DCO. + + Data channel offload currently requires data-ciphers to only contain + AEAD ciphers (AES-GCM and Chacha20-Poly1305) and Linux with the + ovpn-dco module. + + Note that some options have no effect or not available when + DCO mode is enabled. + + A platforms that do not support DCO ``disable-dco`` has no effect. diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 5883c291..0cc06155 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -30,6 +30,7 @@ AM_CFLAGS = \ $(OPTIONAL_LZ4_CFLAGS) \ $(OPTIONAL_PKCS11_HELPER_CFLAGS) \ $(OPTIONAL_INOTIFY_CFLAGS) \ + ${OPTIONAL_DCO_CFLAGS} \ -DPLUGIN_LIBDIR=\"${plugindir}\" if WIN32 @@ -53,6 +54,7 @@ openvpn_SOURCES = \ crypto.c crypto.h crypto_backend.h \ crypto_openssl.c crypto_openssl.h \ crypto_mbedtls.c crypto_mbedtls.h \ + dco.c dco.h \ dhcp.c dhcp.h \ env_set.c env_set.h \ errlevel.h \ @@ -85,7 +87,8 @@ openvpn_SOURCES = \ multi.c multi.h \ networking_iproute2.c networking_iproute2.h \ networking_sitnl.c networking_sitnl.h \ - networking.h \ + networking_linuxdco.c networking_linuxdco.h \ + networking.h \ ntlm.c ntlm.h \ occ.c occ.h \ openssl_compat.h \ @@ -141,7 +144,8 @@ openvpn_LDADD = \ $(OPTIONAL_SELINUX_LIBS) \ $(OPTIONAL_SYSTEMD_LIBS) \ $(OPTIONAL_DL_LIBS) \ - $(OPTIONAL_INOTIFY_LIBS) + $(OPTIONAL_INOTIFY_LIBS) \ + $(OPTIONAL_DCO_LIBS) if WIN32 openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h ring_buffer.h openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index a63a2619..57869c66 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -826,6 +826,16 @@ init_key_ctx(struct key_ctx *ctx, const struct key *key, cipher_kt_iv_size(kt->cipher)); warn_insecure_key_type(ciphername, kt->cipher); } + +#if defined(ENABLE_DCO) + /* Keep key material for DCO */ + static_assert(sizeof(key->cipher) == sizeof(ctx->aead_key), "DCO key size mismatch"); + if (kt->keep_key_data) + { + memcpy(ctx->aead_key, key->cipher, sizeof(ctx->aead_key)); + } +#endif + if (kt->digest) { ctx->hmac = hmac_ctx_new(); diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 1e2ca3cb..bec6883c 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -140,6 +140,9 @@ struct key_type { const cipher_kt_t *cipher; /**< Cipher static parameters */ const md_kt_t *digest; /**< Message digest static parameters */ +#if defined(ENABLE_DCO) + bool keep_key_data; +#endif }; /** @@ -166,6 +169,9 @@ struct key_ctx uint8_t implicit_iv[OPENVPN_MAX_IV_LENGTH]; /**< The implicit part of the IV */ size_t implicit_iv_len; /**< The length of implicit_iv */ +#if defined(ENABLE_DCO) + uint8_t aead_key[MAX_CIPHER_KEY_LENGTH]; /**< Keeps the key data for use with DCO */ +#endif }; #define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */ diff --git a/src/openvpn/dco.c b/src/openvpn/dco.c new file mode 100644 index 00000000..b04122b6 --- /dev/null +++ b/src/openvpn/dco.c @@ -0,0 +1,272 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2021 Arne Schwabe + * Copyright (C) 2021 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + + +#include "syshead.h" + +#include "errlevel.h" +#include "networking.h" + +#include "multi.h" +#include "dco.h" +#include "networking_linuxdco.h" + +#if defined(ENABLE_DCO) +#include "ssl_verify.h" + +bool +dco_do_key_dance(struct tuntap *tt, struct tls_multi *multi, const char *ciphername) +{ + struct key_state *primary = tls_select_encryption_key(multi); + struct key_state *secondary = NULL; + + for (int i = 0; i < KEY_SCAN_SIZE; ++i) + { + struct key_state *ks = get_key_scan(multi, i); + struct key_ctx_bi *key = &ks->crypto_options.key_ctx_bi; + + if (ks == primary) + { + continue; + } + + if (ks->state >= S_GENERATED_KEYS) + { + ASSERT(ks->authenticated == KS_AUTH_TRUE); + ASSERT(key->initialized); + + secondary = ks; + } + } + + if (!primary) + { + if (multi->dco_keys_installed >= 1) + { + msg(D_DCO, "DCO: No encryption key found. Purging data channel keys"); + dco_del_key(tt, multi->peer_id, OVPN_KEY_SLOT_PRIMARY); + if (multi->dco_keys_installed == 2) + { + dco_del_key(tt, multi->peer_id, OVPN_KEY_SLOT_SECONDARY); + } + multi->dco_keys_installed = 2; + } + return false; + } + + /* All keys installed as they should */ + if (primary->dco_status == DCO_INSTALLED_PRIMARY + && (!secondary || secondary->dco_status == DCO_INSTALLED_SECONDARY)) + { + /* Check if we have a previously installed secondary key */ + if (!secondary && multi->dco_keys_installed == 2) + { + multi->dco_keys_installed = 1; + dco_del_key(tt, multi->peer_id, OVPN_KEY_SLOT_SECONDARY); + } + return true; + } + + int pid = primary->key_id; + int sid = secondary ? secondary->key_id : -1; + + msg(D_DCO_DEBUG, "Installing DCO data channel keys for peer %d, " + "primary key-id: %d, secondary key-id: %d.", + multi->peer_id, pid, sid); + + /* General strategy, get primary key installed correctly first. If that is + * okay then check if we need to exchange secondary */ + if (primary->dco_status != DCO_INSTALLED_PRIMARY) + { + /* ovpn-win-dco does not like to have the install as secondary and then + * swap to primary for the first key .... */ + if (multi->dco_keys_installed == 0) + { + dco_new_key(tt, multi->peer_id, OVPN_KEY_SLOT_PRIMARY, primary, ciphername); + multi->dco_keys_installed = 1; + } + else + { + if (primary->dco_status != DCO_INSTALLED_SECONDARY) + { + dco_new_key(tt, multi->peer_id, OVPN_KEY_SLOT_SECONDARY, primary, ciphername); + } + dco_swap_keys(tt, multi->peer_id); + } + primary->dco_status = DCO_INSTALLED_PRIMARY; + + /* if the secondary was installed as primary before the swap demoted + * it to secondary */ + if (secondary && secondary->dco_status == DCO_INSTALLED_PRIMARY) + { + secondary->dco_status = DCO_INSTALLED_SECONDARY; + multi->dco_keys_installed = 2; + } + } + + /* The primary key is now the correct key but the secondary key might + * already a new key that will be later promoted to primary key and we + * need to install the key */ + if (secondary && secondary->dco_status != DCO_INSTALLED_SECONDARY) + { + dco_new_key(tt, multi->peer_id, OVPN_KEY_SLOT_SECONDARY, secondary, ciphername); + secondary->dco_status = DCO_INSTALLED_SECONDARY; + multi->dco_keys_installed = 2; + } + /* delete an expired key */ + if (!secondary && multi->dco_keys_installed == 2) + { + dco_del_key(tt, multi->peer_id, OVPN_KEY_SLOT_SECONDARY); + multi->dco_keys_installed = 1; + } + + /* All keys that we have not installed are set to NOT installed */ + for (int i = 0; i < KEY_SCAN_SIZE; ++i) + { + struct key_state *ks = get_key_scan(multi, i); + if (ks != primary && ks != secondary) + { + ks->dco_status = DCO_NOT_INSTALLED; + } + } + return true; +} + +int +get_dco_cipher(const char *cipher) +{ + if (streq(cipher, "AES-256-GCM") || streq(cipher, "AES-128-GCM") || + streq(cipher, "AES-192-GCM")) + return OVPN_CIPHER_ALG_AES_GCM; + else if (streq(cipher, "CHACHA20-POLY1305")) + { + return OVPN_CIPHER_ALG_CHACHA20_POLY1305; + } + else if (strcmp(cipher, "none") == 0) + { + return OVPN_CIPHER_ALG_NONE; + } + else + { + return -ENOTSUP; + } +} +#endif + +/* These methods are currently Linux specified but likely to be used any platform that implements Server side DCO */ +#if defined(ENABLE_LINUXDCO) + +void +dco_install_iroute(struct multi_context *m, struct multi_instance *mi, + struct mroute_addr *addr, bool primary) +{ + if (!dco_enabled(&m->top.options)) + { + return; + } + + if (primary) + { + /* We do not want to install IP -> IP dev ovpn-dco0 */ + return; + } + + int addrtype = (addr->type & MR_ADDR_MASK); + + /* If we do not have local IP addr to install, skip the route */ + if ((addrtype == MR_ADDR_IPV6 && !mi->context.c2.push_ifconfig_ipv6_defined) + || (addrtype == MR_ADDR_IPV4 && !mi->context.c2.push_ifconfig_defined)) + { + return; + } + + struct context *c = &mi->context; + const char *dev = c->c1.tuntap->actual_name; + + if (addrtype == MR_ADDR_IPV6) + { + net_route_v6_add(&m->top.net_ctx, &addr->v6.addr, addr->netbits, + &mi->context.c2.push_ifconfig_ipv6_local, dev, 0, + DCO_IROUTE_METRIC); + } + else if (addrtype == MR_ADDR_IPV4) + { + in_addr_t dest = htonl(addr->v4.addr); + net_route_v4_add(&m->top.net_ctx, &dest, addr->netbits, + &mi->context.c2.push_ifconfig_local, dev, 0, + DCO_IROUTE_METRIC); + } +} + +void +dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi) +{ + if (!dco_enabled(&m->top.options)) + { + return; + } + ASSERT(TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN); + + struct context *c = &mi->context; + const char *dev = c->c1.tuntap->actual_name; + + if (mi->context.c2.push_ifconfig_defined) + { + for (const struct iroute *ir = c->options.iroutes; ir != NULL; ir = ir->next) + { + net_route_v4_del(&m->top.net_ctx, &ir->network, ir->netbits, + &mi->context.c2.push_ifconfig_local, dev, + 0, DCO_IROUTE_METRIC); + } + } + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + for (const struct iroute_ipv6 *ir6 = c->options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) + { + net_route_v6_del(&m->top.net_ctx, &ir6->network, ir6->netbits, + &mi->context.c2.push_ifconfig_ipv6_local, dev, + 0, DCO_IROUTE_METRIC); + } + } +} +#else +void +dco_install_iroute(struct multi_context *m, struct multi_instance *mi, + struct mroute_addr *addr, bool primary) +{ +} + +void +dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi) +{ +} +#endif \ No newline at end of file diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h new file mode 100644 index 00000000..1cfdc8fb --- /dev/null +++ b/src/openvpn/dco.h @@ -0,0 +1,118 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2021 Arne Schwabe + * Copyright (C) 2021 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef DCO_H +#define DCO_H + +/* forward declarations, including multi.h leads to nasty include + * order problems */ +struct multi_context; +struct tls_multi; +struct multi_instance; +struct mroute_addr; +struct tuntap; + +#if !defined(ENABLE_DCO) +/* Define dummy type for dco context if DCO is not enabled */ +typedef void *dco_context_t; + +static inline void open_tun_dco(struct tuntap *tt, const char* dev) { ASSERT(false); } + +static inline void close_tun_dco(struct tuntap *tt) { ASSERT(false); } +#else +#include "networking_linuxdco.h" +#include "crypto.h" + +/* forward declarations */ +struct tuntap; +struct key_state; + +void open_tun_dco(struct tuntap *tt, const char* dev); + +void close_tun_dco(struct tuntap *tt); + +int dco_new_peer(struct tuntap *tt, unsigned int peerid, int sd, + struct sockaddr *localaddr, struct sockaddr *remoteaddr, + struct in_addr *remote_in4, struct in6_addr *remote_in6); + + +int ovpn_set_peer(struct tuntap *tt, unsigned int peerid, + unsigned int keepalive_interval, + unsigned int keepalive_timeout); + +int ovpn_do_read_dco(struct dco_context *dco); +int dco_del_peer(struct tuntap *tt, unsigned int peerid); + +int +dco_del_key(struct tuntap *tt, unsigned int peerid, ovpn_key_slot_t slot); + +int +dco_new_key(struct tuntap *tt, unsigned int peerid, ovpn_key_slot_t slot, + struct key_state *ks, const char* ciphername); + +int dco_swap_keys(struct tuntap *tt, unsigned int peerid); + +/** + * Does the assertions that the key material is indeed sane. + * @param key the key context to be checked + */ +static inline void dco_check_key_ctx(const struct key_ctx_bi *key) +{ + ASSERT(key->initialized); + /* Double check that we do not have empty keys */ + const uint8_t empty_key[32] = { 0 }; + ASSERT(memcmp(key->encrypt.aead_key, empty_key, 32)); + ASSERT(memcmp(key->decrypt.aead_key, empty_key, 32)); +} + +#endif + +void +dco_install_iroute(struct multi_context *m, struct multi_instance *mi, + struct mroute_addr *addr, bool primary); + +void +dco_delete_iroutes(struct multi_context *m, struct multi_instance *mi); + + +/** + * This function will check if the encryption and decryption keys are installed + * to the data channel offload and if not do the necessary steps to ensure that + * openvpn and data channel are synced again + * + * @param tt Tun tap device context + * @param multi TLS multi instance + * @param ciphername Ciphername to use when installing the keys. + * @return + */ +bool +dco_do_key_dance(struct tuntap *tt, struct tls_multi *multi, const char *ciphername); + +/** + * Translates an OpenVPN Cipher string to a supported cipher enum from DCO + * @param cipher OpenVPN cipher string + * @return constant that defines the cipher or -ENOTSUP if not supported + */ +int get_dco_cipher(const char *cipher); +#endif \ No newline at end of file diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index 602e48a8..a7054647 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -91,6 +91,7 @@ #define D_OSBUF LOGLEV(3, 43, 0) /* show socket/tun/tap buffer sizes */ #define D_PS_PROXY LOGLEV(3, 44, 0) /* messages related to --port-share option */ #define D_IFCONFIG LOGLEV(3, 0, 0) /* show ifconfig info (don't mute) */ +#define D_DCO LOGLEV(3, 0, 0) /* show DCO related messages */ #define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */ #define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */ @@ -113,6 +114,7 @@ #define D_TUN_RW LOGLEV(6, 69, M_DEBUG) /* show TUN/TAP reads/writes */ #define D_TAP_WIN_DEBUG LOGLEV(6, 69, M_DEBUG) /* show TAP-Windows driver debug info */ #define D_CLIENT_NAT LOGLEV(6, 69, M_DEBUG) /* show client NAT debug info */ +#define D_DCO_DEBUG LOGLEV(6, 69, M_DEBUG) /* show DCO related lowlevel debug messages */ #define D_SHOW_KEYS LOGLEV(7, 70, M_DEBUG) /* show data channel encryption keys */ #define D_SHOW_KEY_SOURCE LOGLEV(7, 70, M_DEBUG) /* show data channel key source entropy */ diff --git a/src/openvpn/event.h b/src/openvpn/event.h index d67d69f6..fc815a59 100644 --- a/src/openvpn/event.h +++ b/src/openvpn/event.h @@ -72,6 +72,9 @@ #define MANAGEMENT_WRITE (1 << (MANAGEMENT_SHIFT + WRITE_SHIFT)) #define FILE_SHIFT 8 #define FILE_CLOSED (1 << (FILE_SHIFT + READ_SHIFT)) +#define DCO_SHIFT 10 +#define DCO_READ (1 << (DCO_SHIFT + READ_SHIFT)) +#define DCO_WRITE (1 << (DCO_SHIFT + WRITE_SHIFT)) /* * Initialization flags passed to event_set_init diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 41ef12e3..02aa6659 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -41,6 +41,7 @@ #include "dhcp.h" #include "common.h" #include "ssl_verify.h" +#include "dco.h" #include "memdbg.h" @@ -50,7 +51,6 @@ counter_type link_read_bytes_global; /* GLOBAL */ counter_type link_write_bytes_global; /* GLOBAL */ /* show event wait debugging info */ - #ifdef ENABLE_DEBUG static const char * @@ -139,6 +139,22 @@ context_reschedule_sec(struct context *c, int sec) c->c2.timeval.tv_usec = 0; } } +#if defined(ENABLE_DCO) +static void +check_dco_key_status(struct context *c) +{ + /* DCO context is not yet initialised or enabled */ + if ((!c->c2.did_open_tun && !c->c1.tuntap)|| !dco_enabled(&c->options)) + { + return; + } + + struct tls_multi *multi = c->c2.tls_multi; + + dco_do_key_dance(c->c1.tuntap, multi, c->options.ciphername); +} +#endif + /* * In TLS mode, let TLS level respond to any control-channel @@ -181,6 +197,13 @@ check_tls(struct context *c) } interval_schedule_wakeup(&c->c2.tmp_int, &wakeup); +#if defined(ENABLE_DCO) + /* Our current code has no good hooks in the TLS machinery to install + * the keys to DCO. So we check/install keys after the whole TLS + * machinery has been completed + */ + check_dco_key_status(c); +#endif if (wakeup) { @@ -1084,6 +1107,15 @@ process_incoming_link(struct context *c) perf_pop(); } +#if defined(ENABLE_LINUXDCO) +static void +process_incoming_dco(struct context *c) +{ + msg(M_INFO, __func__); + ovpn_do_read_dco(&c->c1.tuntap->dco); +} +#endif + /* * Output: c->c2.buf */ @@ -1605,9 +1637,17 @@ process_outgoing_link(struct context *c) socks_preprocess_outgoing_link(c, &to_addr, &size_delta); /* Send packet */ - size = link_socket_write(c->c2.link_socket, - &c->c2.to_link, - to_addr); +#if defined(ENABLE_LINUXDCO) + if (c->c2.link_socket->info.dco_installed) + { + size = ovpn_do_write_dco(&c->c1.tuntap->dco, c->c2.tls_multi->peer_id, &c->c2.to_link); + } + else +#endif + { + size = link_socket_write(c->c2.link_socket, &c->c2.to_link, + to_addr); + } /* Undo effect of prepend */ link_socket_write_post_size_adjust(&size, size_delta, &c->c2.to_link); @@ -1870,6 +1910,9 @@ io_wait_dowork(struct context *c, const unsigned int flags) #ifdef ENABLE_ASYNC_PUSH static int file_shift = FILE_SHIFT; #endif +#ifdef ENABLE_LINUXDCO + static int dco_shift = 10; /* Event from DCO module */ +#endif /* * Decide what kind of events we want to wait for. @@ -1977,6 +2020,12 @@ io_wait_dowork(struct context *c, const unsigned int 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); +#if defined(ENABLE_LINUXDCO) + if (socket & EVENT_READ && c->c2.did_open_tun) + { + dco_event_set(&c->c1.tuntap->dco, c->c2.event_set, (void *) &dco_shift); + } +#endif #ifdef ENABLE_MANAGEMENT if (management) @@ -2099,4 +2148,13 @@ process_io(struct context *c) process_incoming_tun(c); } } +#if defined(ENABLE_LINUXDCO) + else if (status & DCO_READ) + { + if(!IS_SIG(c)) + { + process_incoming_dco(c); + } + } +#endif } diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4fee7f49..4668fd04 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -53,6 +53,7 @@ #include "tls_crypt.h" #include "forward.h" #include "auth_token.h" +#include "dco.h" #include "memdbg.h" @@ -1367,15 +1368,25 @@ do_init_timers(struct context *c, bool deferred) } /* initialize pings */ - - if (c->options.ping_send_timeout) +#if defined(ENABLE_DCO) + if (dco_enabled(&c->options)) { - event_timeout_init(&c->c2.ping_send_interval, c->options.ping_send_timeout, 0); + /* The DCO kernel module will send the pings instead of user space */ + event_timeout_clear(&c->c2.ping_rec_interval); + event_timeout_clear(&c->c2.ping_send_interval); } - - if (c->options.ping_rec_timeout) + else +#endif { - event_timeout_init(&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); + if (c->options.ping_send_timeout) + { + event_timeout_init(&c->c2.ping_send_interval, c->options.ping_send_timeout, 0); + } + + if (c->options.ping_rec_timeout) + { + event_timeout_init(&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); + } } if (!deferred) @@ -2097,6 +2108,7 @@ tun_abort(void) * Handle delayed tun/tap interface bringup due to --up-delay or --pull */ + /** * Helper for do_up(). Take two option hashes and return true if they are not * equal, or either one is all-zeroes. @@ -2110,6 +2122,85 @@ options_hash_changed_or_zero(const struct sha256_digest *a, || !memcmp(a, &zero, sizeof(struct sha256_digest)); } +#ifdef ENABLE_DCO +static bool +p2p_dco_add_new_peer(struct context *c) +{ + struct tls_multi *multi = c->c2.tls_multi; + struct link_socket *ls = c->c2.link_socket; + + if (!dco_enabled(&c->options)) + { + return true; + } + + struct in6_addr remote_ip6 = { 0 }; + struct in_addr remote_ip4 = { 0 }; + + struct in6_addr *remote_addr6 = NULL; + struct in_addr *remote_addr4 = NULL; + + const char* gw = NULL; + /* In client mode if a P2P style topology is used we assume the + * remote-gateway is the IP of the peer */ + if (c->options.topology == TOP_NET30 || c->options.topology == TOP_P2P) + { + gw = c->options.ifconfig_remote_netmask; + } + if (c->options.route_default_gateway) + { + gw = c->options.route_default_gateway; + } + + /* These inet_pton conversion are fatal since options.c already implements + * checks to have only valid addresses when setting the options */ + if (c->options.ifconfig_ipv6_remote) + { + if (inet_pton(AF_INET6, c->options.ifconfig_ipv6_remote, &remote_ip6) != 1) + { + msg(M_FATAL, + "DCO peer init: problem converting IPv6 ifconfig remote address %s to binary", + c->options.ifconfig_ipv6_remote); + } + remote_addr6 = &remote_ip6; + } + + if (gw) + { + if (inet_pton(AF_INET, gw, &remote_ip4) != 1) + { + msg(M_FATAL, "DCO peer init: problem converting IPv4 ifconfig gateway address %s to binary", gw); + } + remote_addr4 = &remote_ip4; + } + else if (c->options.ifconfig_local) + { + msg(M_INFO, "DCO peer init: Need a peer VPN addresss to setup IPv4 (set --route-gateway)"); + } + + if (!c->c2.link_socket->info.dco_installed) + { + ASSERT(ls->info.connection_established); + + struct sockaddr *remoteaddr = &ls->info.lsa->actual.dest.addr.sa; + + dco_new_peer(c->c1.tuntap, multi->peer_id, c->c2.link_socket->sd, NULL, + remoteaddr, remote_addr4, remote_addr6); + + c->c2.tls_multi->dco_peer_added = true; + c->c2.link_socket->info.dco_installed = true; + } + + if (c->options.ping_send_timeout) + { + ovpn_set_peer(c->c1.tuntap, multi->peer_id, c->options.ping_send_timeout, + c->options.ping_rec_timeout); + } + + return true; +} +#endif + bool do_up(struct context *c, bool pulled_options, unsigned int option_types_found) { @@ -2161,6 +2252,11 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) if (c->c2.did_open_tun) { + /* If we are in DCO mode we need to set the new peer options now */ +#if defined(ENABLE_DCO) + p2p_dco_add_new_peer(c); +#endif + c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; /* if --route-delay was specified, start timer */ @@ -2288,6 +2384,18 @@ do_deferred_p2p_ncp(struct context *c) return true; } + +static bool check_dco_pull_options(struct options *o) +{ + if (!o->use_peer_id) + { + msg(D_TLS_ERRORS, "OPTIONS IMPORT: Server did not request DATA_V2 packet " + "format required for data channel offloading"); + return false; + } + return true; +} + /* * Handle non-tun-related pulled options. */ @@ -2400,8 +2508,17 @@ do_deferred_options(struct context *c, const unsigned int found) msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); return false; } - } + /* Check if the pushed options are compatible with DCO if we have DCO + * enabled */ + if (dco_enabled(&c->options) && !check_dco_pull_options(&c->options)) + { + msg(D_TLS_ERRORS, "OPTIONS ERROR: pushed options are incompatible with " + "data channel offloading. Use --disable-dco to connect" + "to this server"); + return false; + } + } return true; } @@ -4332,6 +4449,24 @@ sig: close_context(c, -1, flags); return; } +#if defined(ENABLE_LINUXDCO) +static void remove_dco_peer(struct context *c) +{ + if (!dco_enabled(&c->options)) + { + return; + } + if (c->c1.tuntap && c->c2.tls_multi && c->c2.tls_multi->dco_peer_added) + { + c->c2.tls_multi->dco_peer_added = false; + dco_del_peer(c->c1.tuntap, c->c2.tls_multi->peer_id); + } +} +#else +static void remove_dco_peer(struct context *c) +{ +} +#endif /* * Close a tunnel instance. @@ -4358,6 +4493,10 @@ close_instance(struct context *c) /* free buffers */ do_close_free_buf(c); + /* close peer for DCO if enabled, needs peer-id so must be done before + * closing TLS contexts */ + remove_dco_peer(c); + /* close TLS */ do_close_tls(c); diff --git a/src/openvpn/init.h b/src/openvpn/init.h index 52581f8a..5c719117 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -30,7 +30,7 @@ * Baseline maximum number of events * to wait for. */ -#define BASE_N_EVENTS 4 +#define BASE_N_EVENTS 5 void context_clear(struct context *c); diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index bf9b5190..e335dcef 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -61,6 +61,7 @@ #define MTCP_SIG ((void *)3) /* Only on Windows */ #define MTCP_MANAGEMENT ((void *)4) #define MTCP_FILE_CLOSE_WRITE ((void *)5) +#define MTCP_DCO ((void *)6) #define MTCP_N ((void *)16) /* upper bound on MTCP_x */ @@ -123,6 +124,8 @@ multi_create_instance_tcp(struct multi_context *m) struct hash *hash = m->hash; mi = multi_create_instance(m, NULL); + multi_assign_peer_id(m, mi); + if (mi) { struct hash_element *he; @@ -236,6 +239,7 @@ multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi if (ls && mi->socket_set_called) { event_del(mtcp->es, socket_event_handle(ls)); + mi->socket_set_called = false; } mtcp->n_esr = 0; } @@ -277,6 +281,9 @@ multi_tcp_wait(const struct context *c, } #endif tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, persistent); +#if defined(ENABLE_LINUXDCO) + dco_event_set(&c->c1.tuntap->dco, mtcp->es, MTCP_DCO); +#endif #ifdef ENABLE_MANAGEMENT if (management) @@ -393,6 +400,20 @@ multi_tcp_wait_lite(struct multi_context *m, struct multi_instance *mi, const in tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ +#if defined(ENABLE_LINUXDCO) + if (mi && mi->context.c2.link_socket->info.dco_installed) + { + /* If we got a socket that has been handed over to the kernel + * we must not call the normal socket function to figure out + * if it is readable or writable */ + /* Assert that we only have the DCO exptected flags */ + ASSERT(action & (TA_SOCKET_READ | TA_SOCKET_WRITE)); + + /* We are always ready! */ + return action; + } +#endif + switch (action) { case TA_TUN_READ: @@ -516,7 +537,10 @@ multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int case TA_INITIAL: ASSERT(mi); - multi_tcp_set_global_rw_flags(m, mi); + if (!mi->context.c2.link_socket->info.dco_installed) + { + multi_tcp_set_global_rw_flags(m, mi); + } multi_process_post(m, mi, mpp_flags); break; @@ -566,7 +590,10 @@ multi_tcp_post(struct multi_context *m, struct multi_instance *mi, const int act } else { - multi_tcp_set_global_rw_flags(m, mi); + if (!c->c2.link_socket->info.dco_installed) + { + multi_tcp_set_global_rw_flags(m, mi); + } } break; @@ -623,23 +650,22 @@ multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, /* * Dispatch the action */ - { - struct multi_instance *touched = multi_tcp_dispatch(m, mi, action); + struct multi_instance *touched = multi_tcp_dispatch(m, mi, action); - /* - * Signal received or TCP connection - * reset by peer? - */ - if (touched && IS_SIG(&touched->context)) + /* + * Signal received or TCP connection + * reset by peer? + */ + if (touched && IS_SIG(&touched->context)) + { + if (mi == touched) { - if (mi == touched) - { - mi = NULL; - } - multi_close_instance_on_signal(m, touched); + mi = NULL; } + multi_close_instance_on_signal(m, touched); } + /* * If dispatch produced any pending output * for a particular instance, point to @@ -737,6 +763,13 @@ multi_tcp_process_io(struct multi_context *m) multi_tcp_action(m, mi, TA_INITIAL, false); } } +#if defined(ENABLE_LINUXDCO) + /* incoming data on DCO? */ + else if (e->arg == MTCP_DCO) + { + multi_process_incoming_dco(m); + } +#endif /* signal received? */ else if (e->arg == MTCP_SIG) { diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 07e2caae..1fc391fb 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -227,6 +227,19 @@ multi_process_io_udp(struct multi_context *m) multi_process_file_closed(m, mpp_flags); } #endif +#ifdef ENABLE_LINUXDCO + else if (status & DCO_READ) + { + if(!IS_SIG(&m->top)) + { + bool ret = true; + while (ret) + { + ret = multi_process_incoming_dco(m); + } + } + } +#endif } /* diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 103e882e..650804ea 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -51,6 +51,10 @@ #include "crypto_backend.h" #include "ssl_util.h" +#include "dco.h" + +static void multi_signal_instance(struct multi_context *m, struct multi_instance *mi, const int sig); + /*#define MULTI_DEBUG_EVENT_LOOP*/ @@ -519,6 +523,9 @@ multi_del_iroutes(struct multi_context *m, { const struct iroute *ir; const struct iroute_ipv6 *ir6; + + dco_delete_iroutes(m, mi); + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) { for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) @@ -1224,16 +1231,17 @@ multi_learn_in_addr_t(struct multi_context *m, addr.netbits = (uint8_t) netbits; } - { - struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); + struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); #ifdef ENABLE_MANAGEMENT - if (management && owner) - { - management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); - } -#endif - return owner; + if (management && owner) + { + management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); } +#endif + + dco_install_iroute(m, mi, &addr, primary); + + return owner; } static struct multi_instance * @@ -1257,16 +1265,20 @@ multi_learn_in6_addr(struct multi_context *m, mroute_addr_mask_host_bits( &addr ); } - { - struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); + struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); #ifdef ENABLE_MANAGEMENT - if (management && owner) - { - management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); - } + if (management && owner) + { + management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); + } #endif - return owner; + if (!primary) + { + /* We do not want to install IP -> IP dev ovpn-dco0 */ + dco_install_iroute(m, mi, &addr, primary); } + + return owner; } /* @@ -1764,6 +1776,15 @@ multi_client_set_protocol_options(struct context *c) { tls_multi->use_peer_id = true; } + else if (dco_enabled(o)) + { + msg(M_INFO, "Client does not support DATA_V2. Data channel offloaing " + "requires DATA_V2. Dropping client."); + auth_set_client_reason(tls_multi, "Data channel negotiation " + "failed (missing DATA_V2)"); + return false; + } + if (proto & IV_PROTO_REQUEST_PUSH) { c->c2.push_request_received = true; @@ -1775,7 +1796,6 @@ multi_client_set_protocol_options(struct context *c) o->data_channel_crypto_flags |= CO_USE_TLS_KEY_MATERIAL_EXPORT; } #endif - /* Select cipher if client supports Negotiable Crypto Parameters */ /* if we have already created our key, we cannot *change* our own @@ -2271,12 +2291,127 @@ cleanup: return ret; } +#if defined(ENABLE_LINUXDCO) +#include + +static struct sockaddr * +multi_dco_get_localaddr(struct multi_context *m, struct multi_instance *mi, + struct gc_arena *gc) +{ + struct context *c = &mi->context; + + if ((c->options.sockflags & SF_USE_IP_PKTINFO)) + { + struct link_socket_actual *actual = &c->c2.link_socket_info->lsa->actual; + + switch(actual->dest.addr.sa.sa_family) + { + case AF_INET: + { + struct sockaddr_in *sock_in4; + ALLOC_OBJ_CLEAR_GC(sock_in4, struct sockaddr_in, gc); + sock_in4->sin_addr = actual->pi.in4.ipi_addr; + sock_in4->sin_family = AF_INET; + return (struct sockaddr *) sock_in4; + } + case AF_INET6: + { + struct sockaddr_in6 *sock_in6; + ALLOC_OBJ_CLEAR_GC(sock_in6, struct sockaddr_in6, gc); + sock_in6->sin6_addr = actual->pi.in6.ipi6_addr; + sock_in6->sin6_family = AF_INET6; + return (struct sockaddr *) sock_in6; + } + default: + ASSERT(0); + } + } + else + { + return NULL; + } +} + +static bool +multi_dco_add_new_peer(struct multi_context *m, struct multi_instance *mi) +{ + struct context *c = &mi->context; + + int peer_id = mi->context.c2.tls_multi->peer_id; + int sd = c->c2.link_socket->sd; + struct sockaddr *remoteaddr; + struct sockaddr *local; + + if (c->mode == CM_CHILD_TCP) + { + /* the remote address will be inferred from the TCP socket endpoint */ + remoteaddr = NULL; + } + else + { + ASSERT(c->c2.link_socket_info->connection_established); + remoteaddr = &c->c2.link_socket_info->lsa->actual.dest.addr.sa; + } + + struct in_addr remote_ip4 = { 0 }; + struct in6_addr *remote_addr6 = NULL; + struct in_addr *remote_addr4 = NULL; + struct gc_arena gc = gc_new(); + + /* In server mode we need to fetch the remote addresses from the push config */ + if (c->c2.push_ifconfig_defined) + { + remote_ip4.s_addr = htonl(c->c2.push_ifconfig_local); + remote_addr4 = &remote_ip4; + } + if (c->c2.push_ifconfig_ipv6_defined) + { + remote_addr6 = &c->c2.push_ifconfig_ipv6_local; + } + + local = multi_dco_get_localaddr(m, mi, &gc); + + if (dco_new_peer(c->c1.tuntap, peer_id, sd, local, remoteaddr, + remote_addr4, remote_addr6) != 0) + { + gc_free(&gc); + return false; + } + + c->c2.tls_multi->dco_peer_added = true; + + dco_do_key_dance(c->c1.tuntap, c->c2.tls_multi, c->options.ciphername); + + if (c->options.ping_send_timeout) + { + ovpn_set_peer(c->c1.tuntap, peer_id, c->options.ping_send_timeout, + c->options.ping_rec_timeout); + } + + if (c->mode == CM_CHILD_TCP ) + { + multi_tcp_dereference_instance(m->mtcp, mi); + if (close(sd)) + { + msg(D_DCO|M_ERRNO, "error closing TCP socket after DCO handover"); + } + c->c2.link_socket->info.dco_installed = true; + c->c2.link_socket->sd = SOCKET_UNDEFINED; + } + + gc_free(&gc); + + return true; +} +#endif + /** * Generates the data channel keys */ static bool -multi_client_generate_tls_keys(struct context *c) +multi_client_generate_tls_keys(struct multi_context *m, struct multi_instance *mi) { + struct context *c = &mi->context; struct frame *frame_fragment = NULL; #ifdef ENABLE_FRAGMENT if (c->options.ce.fragment) @@ -2293,6 +2428,13 @@ multi_client_generate_tls_keys(struct context *c) return false; } +#if defined(ENABLE_LINUXDCO) + if (dco_enabled(&c->options) && !multi_dco_add_new_peer(m, mi)) + { + return false; + } +#endif + return true; } @@ -2399,7 +2541,7 @@ multi_client_connect_late_setup(struct multi_context *m, } /* Generate data channel keys only if setting protocol options * has not failed */ - else if (!multi_client_generate_tls_keys(&mi->context)) + else if (!multi_client_generate_tls_keys(m, mi)) { mi->context.c2.tls_multi->multi_state = CAS_FAILED; } @@ -2659,6 +2801,14 @@ multi_connection_established(struct multi_context *m, struct multi_instance *mi) (*cur_handler_index)++; } + /* Check if we have forbidding options in the current mode */ + if (dco_enabled(&mi->context.options) + && check_option_conflict_dco(D_MULTI_ERRORS, &mi->context.options)) + { + msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to incompatible options"); + cc_succeeded = false; + } + if (cc_succeeded) { multi_client_connect_late_setup(m, mi, *option_types_found); @@ -3077,6 +3227,98 @@ done: gc_free(&gc); } + +#if defined(ENABLE_LINUXDCO) + +static void +process_incoming_dco_packet(struct multi_context *m, struct multi_instance *mi, dco_context_t *dco) +{ + struct buffer orig_buf = mi->context.c2.buf; + int peer_id = dco->dco_meesage_peer_id; + + mi->context.c2.buf = dco->dco_packet_in; + + multi_process_incoming_link(m, mi, 0); + + mi->context.c2.buf = orig_buf; + if (BLEN(&dco->dco_packet_in) < 1) + { + msg(D_DCO, "Received too short packet for peer %d" , peer_id); + goto done; + } + + uint8_t *ptr = BPTR(&dco->dco_packet_in); + uint8_t op = ptr[0] >> P_OPCODE_SHIFT; + if (op == P_DATA_V2 || op == P_DATA_V2) + { + msg(D_DCO, "DCO: received data channel packet for peer %d" , peer_id); + goto done; + } + done: + buf_init(&dco->dco_packet_in, 0); +} + +static void +process_incoming_del_peer(struct multi_context *m, struct multi_instance *mi, dco_context_t *dco) +{ + const char *reason = "(unknown reason by ovpn-dco)"; + switch (dco->dco_del_peer_reason) + { + case OVPN_DEL_PEER_REASON_EXPIRED: + reason = "ovpn-dco: ping expired"; + break; + case OVPN_DEL_PEER_REASON_TRANSPORT_ERROR: + reason = "ovpn-dco: transport error"; + break; + case OVPN_DEL_PEER_REASON_USERSPACE: + /* This very likely ourselves but might be another process, so + * still process it */ + reason = "ovpn-dco: userspace request"; + break; + } + + /* When kernel already deleted the peer, the socket is no longer + * installed and we don't need to cleanup the state in the kernel */ + mi->context.c2.tls_multi->dco_peer_added = false; + mi->context.sig->signal_text = reason; + multi_signal_instance(m, mi, SIGTERM); + +} + +bool +multi_process_incoming_dco(struct multi_context *m) +{ + dco_context_t *dco = &m->top.c1.tuntap->dco; + + struct multi_instance *mi = NULL; + + int ret = ovpn_do_read_dco(&m->top.c1.tuntap->dco); + + int peer_id = dco->dco_meesage_peer_id; + + if ((peer_id >= 0) && (peer_id < m->max_clients) && (m->instances[peer_id])) + { + mi = m->instances[peer_id]; + if (dco->dco_message_type == OVPN_CMD_PACKET) + { + process_incoming_dco_packet(m, mi, dco); + } + else if (dco->dco_message_type == OVPN_CMD_DEL_PEER) + { + process_incoming_del_peer(m, mi, dco); + } + } + else + { + msg(D_DCO, "Received packet for peer-id unknown to OpenVPN: %d" , peer_id); + } + + dco->dco_message_type = 0; + dco->dco_meesage_peer_id = -1; + return ret > 0; +} +#endif + /* * Process packets in the TCP/UDP socket -> TUN/TAP interface direction, * i.e. client -> server direction. diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 6e85c21c..71883ee5 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -98,7 +98,9 @@ struct client_connect_defer_state * server-mode. */ struct multi_instance { - struct schedule_entry se; /* this must be the first element of the structure */ + struct schedule_entry se; /* this must be the first element of the structure, + * We cast between this and schedule_entry so the + * beginning of the struct must be identical */ struct gc_arena gc; bool halt; int refcount; @@ -308,6 +310,8 @@ void multi_process_float(struct multi_context *m, struct multi_instance *mi); bool multi_process_post(struct multi_context *m, struct multi_instance *mi, const unsigned int flags); +bool multi_process_incoming_dco(struct multi_context *m); + /**************************************************************************/ /** * Demultiplex and process a packet received over the external network diff --git a/src/openvpn/networking.h b/src/openvpn/networking.h index 2f0ee160..cb57802b 100644 --- a/src/openvpn/networking.h +++ b/src/openvpn/networking.h @@ -27,6 +27,7 @@ struct context; #ifdef ENABLE_SITNL #include "networking_sitnl.h" +#include "dco.h" #elif ENABLE_IPROUTE #include "networking_iproute2.h" #else diff --git a/src/openvpn/networking_linuxdco.c b/src/openvpn/networking_linuxdco.c new file mode 100644 index 00000000..ca6284e7 --- /dev/null +++ b/src/openvpn/networking_linuxdco.c @@ -0,0 +1,848 @@ +/* + * Interface to linux dco networking code + * + * Copyright (C) 2020 Antonio Quartulli + * Copyright (C) 2020 Arne Schwabe + * Copyright (C) 2020 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#if defined(ENABLE_LINUXDCO) + +#include "syshead.h" + +#include "errlevel.h" +#include "buffer.h" +#include "networking.h" + +#include "socket.h" +#include "tun.h" +#include "ssl.h" +#include "fdmisc.h" +#include "ssl_verify.h" + +#include + +#include +#include +#include +#include +#include + + +/* libnl < 3.5.0 does not set the NLA_F_NESTED on its own, therefore we + * have to explicitly do it to prevent the kernel from failing upon + * parsing of the message + */ +#define nla_nest_start(_msg, _type) \ + nla_nest_start(_msg, (_type) | NLA_F_NESTED) + +static int ovpn_get_mcast_id(dco_context_t *dco); + +void dco_check_key_ctx(const struct key_ctx_bi *key); + +typedef int (*ovpn_nl_cb)(struct nl_msg *msg, void *arg); + +int +resolve_ovpn_netlink_id(int msglevel) +{ + int ret; + struct nl_sock* nl_sock = nl_socket_alloc(); + + ret = genl_connect(nl_sock); + if (ret) + { + msg(msglevel, "Cannot connect to generic netlink: %s", + nl_geterror(ret)); + goto err_sock; + } + set_cloexec(nl_socket_get_fd(nl_sock)); + + ret = genl_ctrl_resolve(nl_sock, OVPN_NL_NAME); + if (ret < 0) + { + msg(msglevel, "Cannot find ovpn_dco netlink component: %s", + nl_geterror(ret)); + } + +err_sock: + nl_socket_free(nl_sock); + return ret; +} + +static struct nl_msg *ovpn_dco_nlmsg_create(dco_context_t *dco, + enum ovpn_nl_commands cmd) +{ + struct nl_msg *nl_msg = nlmsg_alloc(); + if (!nl_msg) + { + msg(M_ERR, "cannot allocate netlink message"); + return NULL; + } + + genlmsg_put(nl_msg, 0, 0, dco->ovpn_dco_id, 0, 0, cmd, 0); + NLA_PUT_U32(nl_msg, OVPN_ATTR_IFINDEX, dco->ifindex); + + return nl_msg; +nla_put_failure: + nlmsg_free(nl_msg); + msg(M_INFO, "cannot put into netlink message"); + return NULL; +} + +static int ovpn_nl_recvmsgs(dco_context_t *dco, const char *prefix) +{ + int ret = nl_recvmsgs(dco->nl_sock, dco->nl_cb); + + switch (ret) { + case -NLE_INTR: + msg(M_WARN, "%s: netlink received interrupt due to signal - ignoring", prefix); + break; + case -NLE_NOMEM: + msg(M_ERR, "%s: netlink out of memory error", prefix); + break; + case -M_ERR: + msg(M_WARN, "%s: netlink reports blocking read - aborting wait", prefix); + break; + case -NLE_NODEV: + msg(M_ERR, "%s: netlink reports device not found:", prefix); + break; + case -NLE_OBJ_NOTFOUND: + msg(M_INFO, "%s: netlink reports object not found, ovpn-dco unloaded?", prefix); + break; + default: + if (ret) + { + msg(M_NONFATAL|M_ERRNO, "%s: netlink reports error (%d): %s", prefix, ret, nl_geterror(-ret)); + } + break; + } + + return ret; +} + +/** + * Send a preprared netlink message and registers cb as callback if non-null. + * + * The method will also free nl_msg + * @param dco The dco context to use + * @param nl_msg the message to use + * @param cb An optional callback if the caller expects an answers\ + * @param prefix A prefix to report in the error message to give the user context + * @return status of sending the message + */ +static int +ovpn_nl_msg_send(dco_context_t *dco, struct nl_msg *nl_msg, ovpn_nl_cb cb, + const char* prefix) +{ + dco->status = 1; + + if (cb) + { + nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, cb, dco); + } + else + { + nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, NULL, dco); + } + + nl_send_auto(dco->nl_sock, nl_msg); + + while (dco->status == 1) + { + ovpn_nl_recvmsgs(dco, prefix); + } + + if (dco->status < 0) + { + msg(M_INFO, "%s: failed to send netlink message: %s (%d)", + prefix, strerror(-dco->status), dco->status); + } + + return dco->status; +} + +struct sockaddr * +mapped_v4_to_v6(struct sockaddr *sock, struct gc_arena *gc) +{ + struct sockaddr_in6 *sock6 = ((struct sockaddr_in6 *)sock); + if (sock->sa_family == AF_INET6 && + memcmp(&sock6->sin6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff", 12)==0) + { + + struct sockaddr_in* sock4; + ALLOC_OBJ_CLEAR_GC(sock4, struct sockaddr_in, gc); + memcpy (&sock4->sin_addr, sock6->sin6_addr.s6_addr +12, 4); + sock4->sin_port = sock6->sin6_port; + sock4->sin_family = AF_INET; + return (struct sockaddr *) sock4; + } + return sock; +} + +int dco_new_peer(struct tuntap *tt, unsigned int peerid, int sd, + struct sockaddr *localaddr, struct sockaddr *remoteaddr, + struct in_addr *remote_in4, struct in6_addr *remote_in6) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd); + + struct gc_arena gc = gc_new(); + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(&tt->dco, OVPN_CMD_NEW_PEER); + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_NEW_PEER); + int ret = -EMSGSIZE; + + NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_PEER_ID, peerid); + NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_SOCKET, sd); + + /* Set the remote endpoint if defined (for UDP) */ + if (remoteaddr) + { + remoteaddr = mapped_v4_to_v6(remoteaddr, &gc); + int alen = af_addr_size(remoteaddr->sa_family); + + NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_SOCKADDR_REMOTE, alen, remoteaddr); + } + + if (localaddr) + { + localaddr = mapped_v4_to_v6(localaddr, &gc); + if (localaddr->sa_family == AF_INET) + { + NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_LOCAL_IP, sizeof(struct in_addr), + &((struct sockaddr_in *)localaddr)->sin_addr); + } + else if (localaddr->sa_family == AF_INET6) + { + NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_LOCAL_IP, sizeof(struct in6_addr), + &((struct sockaddr_in6 *)localaddr)->sin6_addr); + } + } + + /* Set the primary VPN IP addresses of the peer */ + if (remote_in4) + { + NLA_PUT_U32(nl_msg, OVPN_NEW_PEER_ATTR_IPV4, remote_in4->s_addr); + } + if (remote_in6) + { + NLA_PUT(nl_msg, OVPN_NEW_PEER_ATTR_IPV6, sizeof(struct in6_addr), + remote_in6); + } + nla_nest_end(nl_msg, attr); + + + ret = ovpn_nl_msg_send(&tt->dco, nl_msg, NULL, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + gc_free(&gc); + return ret; +} + +static int +ovpn_nl_cb_finish(struct nl_msg (*msg)__attribute__((unused)), void *arg) +{ + int *status = arg; + + *status = 0; + return NL_SKIP; +} + +static int +ovpn_nl_cb_error(struct sockaddr_nl (*nla)__attribute__((unused)), + struct nlmsgerr *err, void *arg) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *)err - 1; + struct nlattr *tb_msg[NLMSGERR_ATTR_MAX + 1]; + int len = nlh->nlmsg_len; + struct nlattr *attrs; + int *ret = arg; + int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); + + *ret = err->error; + + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + return NL_STOP; + + if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) + ack_len += err->msg.nlmsg_len - sizeof(*nlh); + + if (len <= ack_len) + return NL_STOP; + + attrs = (void *)((unsigned char *)nlh + ack_len); + len -= ack_len; + + nla_parse(tb_msg, NLMSGERR_ATTR_MAX, attrs, len, NULL); + if (tb_msg[NLMSGERR_ATTR_MSG]) { + len = strnlen((char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]), + nla_len(tb_msg[NLMSGERR_ATTR_MSG])); + msg(M_WARN, "kernel error: %*s\n", len, + (char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG])); + } + + return NL_STOP; +} + +static void +ovpn_dco_init_netlink(dco_context_t *dco) +{ + dco->ovpn_dco_id = resolve_ovpn_netlink_id(M_ERR); + + dco->nl_sock = nl_socket_alloc(); + + + if (!dco->nl_sock) + { + msg(M_ERR, "Cannot create netlink socket"); + } + + /* TODO: Why are we setting this buffer size? */ + nl_socket_set_buffer_size(dco->nl_sock, 8192, 8192); + + int ret = genl_connect(dco->nl_sock); + if (ret) + { + msg(M_ERR, "Cannot connect to generic netlink: %s", + nl_geterror(ret)); + } + + set_cloexec(nl_socket_get_fd(dco->nl_sock)); + + dco->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!dco->nl_cb) + { + msg(M_ERR, "failed to allocate netlink callback"); + } + + nl_socket_set_cb(dco->nl_sock, dco->nl_cb); + + nl_cb_err(dco->nl_cb, NL_CB_CUSTOM, ovpn_nl_cb_error, &dco->status); + nl_cb_set(dco->nl_cb, NL_CB_FINISH, NL_CB_CUSTOM, ovpn_nl_cb_finish, + &dco->status); + nl_cb_set(dco->nl_cb, NL_CB_ACK, NL_CB_CUSTOM, ovpn_nl_cb_finish, + &dco->status); + + /* The async PACKET messages confuse libnl and it will drop them with + * wrong sequence numbers (NLE_SEQ_MISMATCH), so disable libnl's sequence + * number check */ + nl_socket_disable_seq_check(dco->nl_sock); +} + +static void +ovpn_dco_uninit_netlink(dco_context_t *dco) +{ + nl_socket_free(dco->nl_sock); + dco->nl_sock = NULL; + + /* Decrease reference count */ + nl_cb_put(dco->nl_cb); + + memset(dco, 0, sizeof(*dco)); +} + +static void ovpn_dco_register(dco_context_t *dco) +{ + msg(D_DCO_DEBUG, __func__); + ovpn_get_mcast_id(dco); + + if (dco->ovpn_dco_mcast_id < 0) + { + msg(M_ERR, "cannot get mcast group: %s", nl_geterror(dco->ovpn_dco_mcast_id)); + } + + /* Register for Ovpn dco specific messages */ + int ret = nl_socket_add_membership(dco->nl_sock, dco->ovpn_dco_mcast_id); + if (ret) + { + msg(M_ERR, "%s: failed to join groups: %d", __func__, ret); + } + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_REGISTER_PACKET); + if (!nl_msg) + { + msg(M_ERR, "%s: cannot allocate message to register for control packets", + __func__); + } + + ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); + if (ret) + { + msg(M_ERR, "%s: failed to register for control packets: %d", __func__, + ret); + } + nlmsg_free(nl_msg); +} + +void +open_tun_dco(struct tuntap *tt, const char* dev) +{ + msg(D_DCO_DEBUG, __func__); + ASSERT(tt->type == DEV_TYPE_TUN); + + ovpn_dco_init_netlink(&tt->dco); + + if (!strcmp(dev, "tun")) + { + /* If no specific name has been requested use an auto-assigned name */ + dev = NULL; + } + + tt->dco.ifindex = net_iface_new(dev, "ovpn-dco"); + + char if_name[IFNAMSIZ]; + if(!if_indextoname(tt->dco.ifindex, if_name)) + { + msg(M_ERR|M_ERRNO, "Cannot resolve interface name for dco interface: "); + } + tt->actual_name = string_alloc(if_name, NULL); + uint8_t *dcobuf = malloc(65536); + buf_set_write(&tt->dco.dco_packet_in, dcobuf, 65536); + tt->dco.dco_meesage_peer_id = -1; + + ovpn_dco_register(&tt->dco); +} + +void +close_tun_dco(struct tuntap *tt) +{ + msg(D_DCO_DEBUG, __func__); + + net_iface_del_index(tt->dco.ifindex); + ovpn_dco_uninit_netlink(&tt->dco); + free(tt->dco.dco_packet_in.data); +} + +int dco_swap_keys(struct tuntap *tt, unsigned int peerid) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid); + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(&tt->dco, OVPN_CMD_SWAP_KEYS); + if (!nl_msg) + return -ENOMEM; + + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_SWAP_KEYS); + int ret = -EMSGSIZE; + NLA_PUT_U32(nl_msg, OVPN_SWAP_KEYS_ATTR_PEER_ID, peerid); + nla_nest_end(nl_msg, attr); + + ret = ovpn_nl_msg_send(&tt->dco, nl_msg, NULL, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + + +int dco_del_peer(struct tuntap *tt, unsigned int peerid) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peerid); + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(&tt->dco, OVPN_CMD_DEL_PEER); + if (!nl_msg) + return -ENOMEM; + + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_DEL_PEER); + int ret = -EMSGSIZE; + NLA_PUT_U32(nl_msg, OVPN_DEL_PEER_ATTR_PEER_ID, peerid); + nla_nest_end(nl_msg, attr); + + ret = ovpn_nl_msg_send(&tt->dco, nl_msg, NULL, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + + +int +dco_del_key(struct tuntap *tt, unsigned int peerid, ovpn_key_slot_t slot) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d, slot %d", __func__, peerid, slot); + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(&tt->dco, OVPN_CMD_DEL_KEY); + if (!nl_msg) + return -ENOMEM; + + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_DEL_KEY); + int ret = -EMSGSIZE; + NLA_PUT_U32(nl_msg, OVPN_DEL_KEY_ATTR_PEER_ID, peerid); + NLA_PUT_U8(nl_msg, OVPN_DEL_KEY_ATTR_KEY_SLOT, slot); + nla_nest_end(nl_msg, attr); + + ret = ovpn_nl_msg_send(&tt->dco, nl_msg, NULL, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + +int +dco_new_key(struct tuntap *tt, unsigned int peerid, ovpn_key_slot_t slot, + struct key_state *ks, const char* ciphername) +{ + msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s", + __func__, slot, ks->key_id, peerid, ciphername); + const int nonce_len = 8; + + struct key_ctx_bi *key = &ks->crypto_options.key_ctx_bi; + + dco_check_key_ctx(key); + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(&tt->dco, OVPN_CMD_NEW_KEY); + if (!nl_msg) + return -ENOMEM; + + int dco_cipher = get_dco_cipher(ciphername); + ASSERT(dco_cipher >= 0); + + + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_NEW_KEY); + int ret = -EMSGSIZE; + NLA_PUT_U32(nl_msg, OVPN_NEW_KEY_ATTR_PEER_ID, peerid); + NLA_PUT_U8(nl_msg, OVPN_NEW_KEY_ATTR_KEY_SLOT, slot); + NLA_PUT_U8(nl_msg, OVPN_NEW_KEY_ATTR_KEY_ID, ks->key_id); + + NLA_PUT_U16(nl_msg, OVPN_NEW_KEY_ATTR_CIPHER_ALG, dco_cipher); + + if (dco_cipher != OVPN_CIPHER_ALG_NONE) + { + size_t key_len = cipher_kt_key_size(cipher_kt_get(ciphername)); + struct nlattr *key_enc = nla_nest_start(nl_msg, OVPN_NEW_KEY_ATTR_ENCRYPT_KEY); + NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, key_len, key->encrypt.aead_key); + NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_NONCE_TAIL, nonce_len, + key->encrypt.implicit_iv); + nla_nest_end(nl_msg, key_enc); + + struct nlattr *key_dec = nla_nest_start(nl_msg, OVPN_NEW_KEY_ATTR_DECRYPT_KEY); + NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, key_len, key->decrypt.aead_key); + NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_NONCE_TAIL, nonce_len, + key->decrypt.implicit_iv); + nla_nest_end(nl_msg, key_dec); + } + else + { + /* Check that --auth is disabled. Normally, we would catch this + * inconsistency earlier but since the "none" is only for debug and + * requires manual editing of DCO_SUPPORTED_CIPHERS, it should be fine + * to abort here */ + if (key->encrypt.hmac != NULL) + { + msg(M_FATAL, "FATAL: DCO with cipher none requires --auth none"); + } + /* ovpn-dco needs empty encrypt/decrypt keys with cipher none */ + struct nlattr *key_enc = nla_nest_start(nl_msg, + OVPN_NEW_KEY_ATTR_ENCRYPT_KEY); + NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, 16, + key->encrypt.aead_key); + nla_nest_end(nl_msg, key_enc); + + struct nlattr *key_dec = nla_nest_start(nl_msg, + OVPN_NEW_KEY_ATTR_DECRYPT_KEY); + NLA_PUT(nl_msg, OVPN_KEY_DIR_ATTR_CIPHER_KEY, 16, + key->decrypt.aead_key); + nla_nest_end(nl_msg, key_dec); + } + nla_nest_end(nl_msg, attr); + + secure_memzero(key->encrypt.aead_key, sizeof (key->encrypt.aead_key)); + secure_memzero(key->decrypt.aead_key, sizeof (key->decrypt.aead_key)); + + ret = ovpn_nl_msg_send(&tt->dco, nl_msg, NULL, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + +int ovpn_set_peer(struct tuntap *tt, unsigned int peerid, + unsigned int keepalive_interval, + unsigned int keepalive_timeout) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d", __func__, peerid, + keepalive_interval, keepalive_timeout); + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(&tt->dco, OVPN_CMD_SET_PEER); + if (!nl_msg) + { + return -ENOMEM; + } + + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_SET_PEER); + int ret = -EMSGSIZE; + NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_PEER_ID, peerid); + NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_KEEPALIVE_INTERVAL, + keepalive_interval); + NLA_PUT_U32(nl_msg, OVPN_SET_PEER_ATTR_KEEPALIVE_TIMEOUT, + keepalive_timeout); + nla_nest_end(nl_msg, attr); + + ret = ovpn_nl_msg_send(&tt->dco, nl_msg, NULL, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + +static int mcast_family_handler(struct nl_msg *msg, void *arg) +{ + dco_context_t *dco = arg; + struct nlattr *tb[CTRL_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[CTRL_ATTR_MCAST_GROUPS]) + return NL_SKIP; + + struct nlattr *mcgrp; + int rem_mcgrp; + nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) + { + struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1]; + + nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX, + nla_data(mcgrp), nla_len(mcgrp), NULL); + + if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || + !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]) + { + continue; + } + + if (strncmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]), + OVPN_NL_MULTICAST_GROUP_PEERS, + nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])) != 0) + { + continue; + } + dco->ovpn_dco_mcast_id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]); + break; + } + + return NL_SKIP; +} +/** + * Lookup the multicast id for OpenVPN. This method and its help method currently + * hardcode the lookup to OVPN_NL_NAME and OVPN_NL_MULTICAST_GROUP_PEERS but + * extended in the future if we need to lookup more than one mcast id. + */ +static int +ovpn_get_mcast_id(dco_context_t *dco) +{ + dco->ovpn_dco_mcast_id = -ENOENT; + + /* Even though 'nlctrl' is a constant, there seem to be no library + * provided define for it */ + int ctrlid = genl_ctrl_resolve(dco->nl_sock, "nlctrl"); + + struct nl_msg *nl_msg = nlmsg_alloc(); + if (!nl_msg) + { + return -ENOMEM; + } + + genlmsg_put(nl_msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0); + + int ret = -EMSGSIZE; + NLA_PUT_STRING(nl_msg, CTRL_ATTR_FAMILY_NAME, OVPN_NL_NAME); + + ret = ovpn_nl_msg_send(dco, nl_msg, mcast_family_handler, __func__); + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + +static int ovpn_handle_msg(struct nl_msg *msg, void *arg) +{ + dco_context_t *dco = arg; + + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attrs[OVPN_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + + if (!genlmsg_valid_hdr(nlh, 0)) + { + msg(D_DCO, "ovpn-dco: invalid header"); + return NL_SKIP; + } + + if (nla_parse(attrs, OVPN_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL)) + { + msg(D_DCO, "received bogus data from ovpn-dco"); + return NL_SKIP; + } + + if (!attrs[OVPN_ATTR_IFINDEX]) + { + msg(D_DCO, "ovpn-dco: Received message without ifindex"); + return NL_SKIP; + } + + uint32_t ifindex = nla_get_u32(attrs[OVPN_ATTR_IFINDEX]); + if (ifindex != dco->ifindex) + { + msg(D_DCO, "ovpn-dco: received message type %d with mismatched ifindex %d\n", + gnlh->cmd, ifindex); + return NL_SKIP; + } + + switch (gnlh->cmd) { + case OVPN_CMD_DEL_PEER: + { + if (!attrs[OVPN_ATTR_DEL_PEER]) + { + msg(D_DCO, "ovpn-dco: no attributes in OVPN_DEL_PEER message"); + return NL_SKIP; + } + + struct nlattr *dp_attrs[OVPN_DEL_PEER_ATTR_MAX + 1]; + if (nla_parse_nested(dp_attrs, OVPN_DEL_PEER_ATTR_MAX, + attrs[OVPN_ATTR_DEL_PEER], NULL)) + { + msg(D_DCO, "received bogus del peer packet data from ovpn-dco"); + return NL_SKIP; + } + + if (!dp_attrs[OVPN_DEL_PEER_ATTR_REASON]) + { + msg(D_DCO, "ovpn-dco: no reason in DEL_PEER message"); + return NL_SKIP; + } + if (!dp_attrs[OVPN_DEL_PEER_ATTR_PEER_ID]) + { + msg(D_DCO, "ovpn-dco: no peer-id in DEL_PEER message"); + return NL_SKIP; + } + int reason = nla_get_u8(dp_attrs[OVPN_DEL_PEER_ATTR_REASON]); + unsigned int peerid = nla_get_u32(dp_attrs[OVPN_DEL_PEER_ATTR_PEER_ID]); + + msg(D_DCO_DEBUG, "ovpn-dco: received CMD_DEL_PEER, ifindex: %d, peer-id %d, reason: %d", + ifindex, peerid, reason); + dco->dco_meesage_peer_id = peerid; + dco->dco_del_peer_reason = reason; + dco->dco_message_type = OVPN_CMD_DEL_PEER; + + break; + } + case OVPN_CMD_PACKET: + { + if (!attrs[OVPN_ATTR_PACKET]) + { + msg(D_DCO, "ovpn-dco: no packet in OVPN_CMD_PACKET message"); + return NL_SKIP; + } + struct nlattr *pkt_attrs[OVPN_PACKET_ATTR_MAX + 1]; + + if (nla_parse_nested(pkt_attrs, OVPN_PACKET_ATTR_MAX, + attrs[OVPN_ATTR_PACKET], NULL)) + { + msg(D_DCO, "received bogus cmd packet data from ovpn-dco"); + return NL_SKIP; + } + if (!pkt_attrs[OVPN_PACKET_ATTR_PEER_ID]) + { + msg(D_DCO, "ovpn-dco: Received OVPN_CMD_PACKET message without peer id"); + return NL_SKIP; + } + if (!pkt_attrs[OVPN_PACKET_ATTR_PACKET]) + { + msg(D_DCO, "ovpn-dco: Received OVPN_CMD_PACKET message without packet"); + return NL_SKIP; + } + + unsigned int peerid = nla_get_u32(pkt_attrs[OVPN_PACKET_ATTR_PEER_ID]); + + uint8_t *data = nla_data(pkt_attrs[OVPN_PACKET_ATTR_PACKET]); + int len = nla_len(pkt_attrs[OVPN_PACKET_ATTR_PACKET]); + + msg(D_DCO_DEBUG, "ovpn-dco: received OVPN_PACKET_ATTR_PACKET, ifindex: %d peer-id: %d, len %d", + ifindex, peerid, len); + if (BLEN(&dco->dco_packet_in) > 0) + { + msg(D_DCO, "DCO packet buffer still full?!"); + return NL_SKIP; + } + buf_init(&dco->dco_packet_in, 0); + buf_write(&dco->dco_packet_in, data, len); + dco->dco_meesage_peer_id = peerid; + dco->dco_message_type = OVPN_CMD_PACKET; + break; + } + default: + msg(D_DCO, "ovpn-dco: received unknown command: %d", gnlh->cmd); + dco->dco_message_type = 0; + return NL_SKIP; + } + + return NL_OK; +} + +int +ovpn_do_read_dco(struct dco_context *dco) +{ + msg(D_DCO_DEBUG, __func__); + nl_cb_set(dco->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ovpn_handle_msg, dco); + + return ovpn_nl_recvmsgs(dco, __func__); +} + +int +ovpn_do_write_dco(dco_context_t *dco, int peer_id, struct buffer *buf) +{ + packet_size_type len = BLEN(buf); + dmsg(D_STREAM_DEBUG, "DCO: WRITE %d offset=%d", (int)len, buf->offset); + + msg(D_DCO_DEBUG, "%s: peer-id %d, len=%d", __func__, peer_id, len); + + struct nl_msg *nl_msg = ovpn_dco_nlmsg_create(dco, OVPN_CMD_PACKET); + + if (!nl_msg) + { + return -ENOMEM; + } + + struct nlattr *attr = nla_nest_start(nl_msg, OVPN_ATTR_PACKET); + int ret = -EMSGSIZE; + NLA_PUT_U32(nl_msg, OVPN_PACKET_ATTR_PEER_ID, peer_id); + NLA_PUT(nl_msg, OVPN_PACKET_ATTR_PACKET, len, BSTR(buf)); + nla_nest_end(nl_msg, attr); + + ret = ovpn_nl_msg_send(dco, nl_msg, NULL, __func__); + if (ret) + { + goto nla_put_failure; + } + + /* return the length of the written data in case of success */ + ret = len; + +nla_put_failure: + nlmsg_free(nl_msg); + return ret; +} + +#endif diff --git a/src/openvpn/networking_linuxdco.h b/src/openvpn/networking_linuxdco.h new file mode 100644 index 00000000..be39437e --- /dev/null +++ b/src/openvpn/networking_linuxdco.h @@ -0,0 +1,85 @@ +/* + * Interface to linux dco networking code + * + * Copyright (C) 2020 Antonio Quartulli + * Copyright (C) 2020 Arne Schwabe + * Copyright (C) 2020 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef NETWORKING_LINUXDCO_H +#define NETWORKING_LINUXDCO_H +#if defined(ENABLE_LINUXDCO) + +#include +#include +#include + +typedef enum ovpn_key_slot ovpn_key_slot_t; + +#include "event.h" + +#define DCO_IROUTE_METRIC 100 + +#define DCO_SUPPORTED_CIPHERS "AES-128-GCM:AES-256-GCM:AES-192-GCM:CHACHA20-POLY1305" + +struct dco_context { + struct nl_sock *nl_sock; + struct nl_cb *nl_cb; + int status; + + int ovpn_dco_id; + int ovpn_dco_mcast_id; + + unsigned int ifindex; + + struct buffer dco_packet_in; + + int dco_message_type; + int dco_meesage_peer_id; + int dco_del_peer_reason; + +}; + +typedef struct dco_context dco_context_t; + + +/** + * @brief resolves the netlink ID for ovpn-dco + * + * This function queries the kernel via a netlink socket + * whether the ovpn-dco netlink namespace is available + * + * This function can be used to determine if the kernel + * support DCO offloading. + * + * @return ID on success, negative error code on error + */ +int +resolve_ovpn_netlink_id(int msglevel); + +static inline void +dco_event_set(struct dco_context *dco, + struct event_set *es, + void *arg) { + if (dco && dco->nl_sock) { + event_ctl(es, nl_socket_get_fd(dco->nl_sock), EVENT_READ, arg); + } +} + +int ovpn_do_write_dco(dco_context_t *dco, int peer_id, struct buffer *buf); + +#endif +#endif diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 65ee6839..b394cd4a 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -253,8 +253,9 @@ - + + @@ -335,6 +336,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index f5fdfcd7..abb591e4 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -39,6 +39,9 @@ Source Files + + Source Files + Source Files @@ -287,6 +290,9 @@ Header Files + + Header Files + Header Files diff --git a/src/openvpn/options.c b/src/openvpn/options.c index ac13412a..a3014415 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -60,6 +60,7 @@ #include "forward.h" #include "ssl_verify.h" #include "platform.h" +#include "dco.h" #include #include "memdbg.h" @@ -105,6 +106,9 @@ const char title_string[] = #endif #endif " [AEAD]" +#ifdef ENABLE_LINUXDCO + " [DCO]" +#endif " built on " __DATE__ ; @@ -3220,6 +3224,133 @@ options_set_backwards_compatible_options(struct options *o) #endif } +#if defined(ENABLE_DCO) +static bool +check_option_conflict_dco_ce(const struct connection_entry *ce, int msglevel) +{ + if (ce->fragment) + { + msg(msglevel, "Note: --fragment disables data channel offload."); + return true; + } + + if (ce->http_proxy_options) + { + msg(msglevel, "Note: --http-proxy disables data channel offload."); + return true; + } + + if (ce->socks_proxy_server) + { + msg(msglevel, "Note --socks-proxy disable data channel offload."); + return true; + } + + return false; +} + +#if defined(ENABLE_LINUXDCO) +static bool check_option_conflict_dco_platform(int msglevel, const struct options *o) +{ + if (resolve_ovpn_netlink_id(D_TUNTAP_INFO) < 0) + { + msg(D_TUNTAP_INFO, "Note: Kernel support for ovpn-dco missing, disabling " + "data channel offload."); + return true; + } + return false; +} +#endif + +bool check_option_conflict_dco(int msglevel, const struct options *o) +{ + if (o->tuntap_options.disable_dco) + { + /* already disabled by --disable-dco, no need to print warnings */ + return true; + } + + if (check_option_conflict_dco_platform(msglevel, o)) + { + return true; + } + + if (dev_type_enum(o->dev, o->dev_type) != DEV_TYPE_TUN) + { + msg(msglevel, "Note: dev-type not tun, disabling data channel offload."); + return true; + } + + /* At this point the ciphers have already been normalised */ + if (o->enable_ncp_fallback + && !tls_item_in_cipher_list(o->ciphername, DCO_SUPPORTED_CIPHERS)) + { + msg(msglevel, "Note: --data-cipher-fallback with cipher '%s' " + "disables data channel offload.", o->ciphername); + return true; + } + + if (o->connection_list) + { + const struct connection_list *l = o->connection_list; + for (int i = 0; i < l->len; ++i) + { + if (check_option_conflict_dco_ce(l->array[i], msglevel)) + { + return true; + } + } + } + else + { + if (check_option_conflict_dco_ce(&o->ce, msglevel)) + { + return true; + } + } + + if (o->mode == MODE_SERVER && o->topology != TOP_SUBNET) + { + msg(msglevel, "Note: NOT using '--topology subnet' disables data channel offload."); + return true; + } + +#ifdef USE_COMP + if(o->comp.alg != COMP_ALG_UNDEF) + { + msg(msglevel, "Note: Using compression disables data channel offload."); + + if (o->mode == MODE_SERVER && !(o->comp.flags & COMP_F_MIGRATE)) + { + /* We can end up here from the multi.c call, only print the + * note if it is not already enabled */ + msg(msglevel, "Consider using the '--compress migrate' option."); + } + return true; + } +#endif + + struct gc_arena gc = gc_new(); + + + char *tmp_ciphers = string_alloc(o->ncp_ciphers, &gc); + const char *token; + while ((token = strsep(&tmp_ciphers, ":"))) + { + if (!tls_item_in_cipher_list(token, DCO_SUPPORTED_CIPHERS)) + { + msg(msglevel, "Note: cipher '%s' in --data-ciphers is not supported " + "by ovpn-dco, disabling data channel offload.", token); + gc_free(&gc); + return true; + } + } + gc_free(&gc); + + return false; +} +#endif /* if defined(TARGET_LINUX) */ + static void options_postprocess_mutate(struct options *o) { @@ -3306,7 +3437,11 @@ options_postprocess_mutate(struct options *o) "option set). "); o->verify_hash_no_ca = true; } - +#if defined(ENABLE_LINUXDCO) + o->tuntap_options.disable_dco = check_option_conflict_dco(D_DCO, o); +#elif defined(TARGET_LINUX) + o->tuntap_options.disable_dco = true; +#endif /* * Save certain parms before modifying options during connect, especially * when using --pull @@ -5643,6 +5778,12 @@ add_option(struct options *options, options->windows_driver = parse_windows_driver(p[1], M_FATAL); } #endif + else if (streq(p[0], "disable-dco") || streq(p[0], "dco-disable")) + { +#if defined(TARGET_LINUX) + options->tuntap_options.disable_dco = true; +#endif + } else if (streq(p[0], "dev-node") && p[1] && !p[2]) { VERIFY_PERMISSION(OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index d4f41cd7..0affc71f 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -862,4 +862,30 @@ void options_string_import(struct options *options, unsigned int *option_types_found, struct env_set *es); +/** + * Returns whether the current configuration has dco enabled. + */ +#ifdef ENABLE_LINUXDCO +static inline bool +dco_enabled(struct options *o) { return !o->tuntap_options.disable_dco; } + +/** + * Checks whether the options struct has any option that is not supported by + * our current dco implementation. If so it prints a warning at warning level + * for the first conflicting option found and returns false + * @param msglevel the msg level to use to print the warnings + * @param o the optiions struct that hold the options + * @return true if a conflict with dco is detected. + */ +bool +check_option_conflict_dco(int msglevel, const struct options *o); +#else +/* Dummy functions to avoid ifdefs in the other code */ + +static inline bool +dco_enabled(struct options *o) { return false; } + +static inline bool +check_option_conflict_dco(int msglevel, struct options *o) { return false; } +#endif #endif /* ifndef OPTIONS_H */ diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index cc1e0c36..57142f4e 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -120,6 +120,7 @@ struct link_socket_info sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ bool bind_ipv6_only; int mtu_changed; /* Set to true when mtu value is changed */ + bool dco_installed; }; /* diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4a4859c3..3e0be874 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1880,6 +1880,10 @@ tls_session_update_crypto_params_do_work(struct tls_session *session, init_key_type(&session->opt->key_type, options->ciphername, options->authname, true, true); +#if defined(ENABLE_DCO) + session->opt->key_type.keep_key_data = dco_enabled(options); +#endif + bool packet_id_long_form = cipher_kt_mode_ofb_cfb(session->opt->key_type.cipher); session->opt->crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); if (packet_id_long_form) @@ -2236,7 +2240,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) { buf_printf(&out, "IV_HWADDR=%s\n", format_hex_ex(rgi.hwaddr, 6, 0, 1, ":", &gc)); } - buf_printf(&out, "IV_SSL=%s\n", get_ssl_library_version() ); + buf_printf(&out, "IV_SSL=%s\n", get_ssl_library_version()); #if defined(_WIN32) buf_printf(&out, "IV_PLAT_VER=%s\n", win32_version_string(&gc, false)); #endif diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index f851bd2b..0da3c1f2 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -167,6 +167,12 @@ enum auth_deferred_result { ACF_FAILED /**< deferred auth has failed */ }; +enum dco_key_status { + DCO_NOT_INSTALLED, + DCO_INSTALLED_PRIMARY, + DCO_INSTALLED_SECONDARY +}; + /** * Security parameter state of one TLS and data channel %key session. * @ingroup control_processor @@ -240,6 +246,8 @@ struct key_state struct auth_deferred_status plugin_auth; struct auth_deferred_status script_auth; + + enum dco_key_status dco_status; }; /** Control channel wrapping (--tls-auth/--tls-crypt) context */ @@ -634,6 +642,11 @@ struct tls_multi /**< Array of \c tls_session objects * representing control channel * sessions with the remote peer. */ + + /* Only used when DCO is used to remember how many keys we installed + * for this session */ + int dco_keys_installed; + bool dco_peer_added; }; /** gets an item of \c key_state objects in the diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 4b95406e..7f5e6fe8 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -489,4 +489,4 @@ p2p_mode_ncp(struct tls_multi *multi, struct tls_session *session) multi->use_peer_id, multi->peer_id, common_cipher); gc_free(&gc); -} \ No newline at end of file +} diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 75d5eaf7..fb3c2e8b 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1957,6 +1957,10 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun { open_null(tt); } + else if (!tt->options.disable_dco) + { + open_tun_dco(tt, dev); + } else { /* @@ -2206,7 +2210,14 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) net_ctx_reset(ctx); } - close_tun_generic(tt); + if (!tt->options.disable_dco) + { + close_tun_dco(tt); + } + else + { + close_tun_generic(tt); + } free(tt); } diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index aa1e47b5..d5beb11c 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -40,6 +40,7 @@ #include "misc.h" #include "networking.h" #include "ring_buffer.h" +#include "networking_linuxdco.h" #ifdef _WIN32 #define WINTUN_COMPONENT_ID "wintun" @@ -138,6 +139,7 @@ struct tuntap_options { struct tuntap_options { int txqueuelen; + bool disable_dco; }; #else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ @@ -218,6 +220,8 @@ struct tuntap /* Some TUN/TAP drivers like to be ioctled for mtu * after open */ int post_open_mtu; + + dco_context_t dco; }; static inline bool diff --git a/tests/unit_tests/openvpn/test_networking.c b/tests/unit_tests/openvpn/test_networking.c index 37b97188..20ac9e94 100644 --- a/tests/unit_tests/openvpn/test_networking.c +++ b/tests/unit_tests/openvpn/test_networking.c @@ -1,7 +1,10 @@ #include "config.h" #include "syshead.h" +#include "error.h" #include "networking.h" +#include "mock_msg.h" + static char *iface = "ovpn-dummy0"; @@ -16,8 +19,10 @@ net__iface_up(bool up) static int net__iface_new(const char *name, const char* type) { - printf("CMD: ip link add %s type %s\n", name, type); - return net_iface_new(name, type); + printf("CMD: ip link add type %s\n", type); + int ifidx = net_iface_new(NULL, type); + printf("ifindex: %d\n", ifidx); + return ifidx; } static int From patchwork Tue Dec 7 01:11:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2115 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director15.mail.ord1d.rsapps.net ([172.27.255.57]) by backend41.mail.ord1d.rsapps.net with LMTP id 6GIhJdtPr2EoLgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:15 -0500 Received: from proxy2.mail.iad3a.rsapps.net ([172.27.255.57]) by director15.mail.ord1d.rsapps.net with LMTP id GDiyNNtPr2FzfgAAIcMcQg (envelope-from ) for ; Tue, 07 Dec 2021 07:13:15 -0500 Received: from smtp33.gate.iad3a ([172.27.255.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy2.mail.iad3a.rsapps.net with LMTPS id EH4WLttPr2GJBgAABcWvHw (envelope-from ) for ; Tue, 07 Dec 2021 07:13: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: smtp33.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 0de1f6f0-5757-11ec-8e4c-525400201c3f-1-1 Received: from [216.105.38.7] ([216.105.38.7:52880] helo=lists.sourceforge.net) by smtp33.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id C9/DB-08843-BDF4FA16; Tue, 07 Dec 2021 07:13:15 -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.94.2) (envelope-from ) id 1muZKU-0002wD-Rl; Tue, 07 Dec 2021 12:12:18 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKN-0002vd-6r for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=txIlf29MTlgqHwmqcyP9f35HujIfPMA7e7DR4Y+Sf84=; b=NyZhopQy1eUEKXUAmsqZme2UET xkidbk8ppPGfCY7X9QZw7J7lCO8rL/iPeiXBoaIpPGbbyiqjDPQyEKulWhFTSFZDhMt1lQw+ClRV4 J7mQMfbPhq3dufX5LktD9cYR3Gq5VQoG/z6vxObjLN0r0w8N7mqd+PnSB9BFp7t3mJvU=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=txIlf29MTlgqHwmqcyP9f35HujIfPMA7e7DR4Y+Sf84=; b=CmgnmTYKPdi7szlGKst3VonrwC GsnkHai8oAEFEnwjMDCP/o8b74ric6iJDVSNinN5PbVxSW8vsOKPOeFcpES3hyplH//NJC6H5dP73 J3xUcQBBNtwxd7EcGO6/lpmFNlNl0jjf2wrm7RkOs4Ohvs9TrGt9QsxG7kN8Q+xrKf08=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKJ-0008P6-B6 for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:10 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:34 +0100 Message-Id: <20211207121137.3221-6-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Arne Schwabe This moves closing the tun handle into its own function and also prints the adapter type we are operating on, instead hardcoding it to tap-windows. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- src/openvpn/tun.c | 75 ++++++++++++++++++++++++++ 1 file changed, 41 insertions [...] Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKJ-0008P6-B6 Subject: [Openvpn-devel] [RFC 5/8] tun: extract close_tun_handle into its own fucntion and print correct type 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: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Arne Schwabe This moves closing the tun handle into its own function and also prints the adapter type we are operating on, instead hardcoding it to tap-windows. Signed-off-by: Arne Schwabe Signed-off-by: Antonio Quartulli --- src/openvpn/tun.c | 75 ++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index fb3c2e8b..d8634ebf 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -6780,6 +6780,46 @@ netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc argv_free(&argv); } +static +void close_tun_handle(struct tuntap* tt) +{ + const char* adaptertype = print_windows_driver(tt->windows_driver); + if (tt->hand != NULL) + { + dmsg(D_WIN32_IO_LOW, "Attempting CancelIO on %s adapter", adaptertype); + if (!CancelIo(tt->hand)) + { + msg(M_WARN | M_ERRNO, "Warning: CancelIO failed on %s adapter", adaptertype); + } + } + + dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped read event on %s adapter", adaptertype); + overlapped_io_close(&tt->reads); + + dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped write event on %s adapter", adaptertype); + overlapped_io_close(&tt->writes); + + if (tt->hand != NULL) + { + dmsg(D_WIN32_IO_LOW, "Attempting CloseHandle on %s adapter", adaptertype); + if (!CloseHandle(tt->hand)) + { + msg(M_WARN | M_ERRNO, "Warning: CloseHandle failed on %s adapter", adaptertype); + } + tt->hand = NULL; + } + + if (tt->windows_driver == WINDOWS_DRIVER_WINTUN) + { + 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); + } +} + void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) { @@ -6849,43 +6889,10 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) dhcp_release(tt); - if (tt->hand != NULL) - { - dmsg(D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Windows adapter"); - if (!CancelIo(tt->hand)) - { - msg(M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Windows adapter"); - } - } - - dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Windows adapter"); - overlapped_io_close(&tt->reads); - - dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Windows adapter"); - overlapped_io_close(&tt->writes); - - if (tt->hand != NULL) - { - dmsg(D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Windows adapter"); - if (!CloseHandle(tt->hand)) - { - msg(M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Windows adapter"); - } - } + close_tun_handle(tt); free(tt->actual_name); - if (tt->windows_driver == WINDOWS_DRIVER_WINTUN) - { - 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); - } - - clear_tuntap(tt); free(tt); gc_free(&gc); From patchwork Tue Dec 7 01:11:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2118 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.28.255.1]) by backend41.mail.ord1d.rsapps.net with LMTP id yH2DMd9Pr2FELgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:19 -0500 Received: from proxy6.mail.ord1c.rsapps.net ([172.28.255.1]) by director11.mail.ord1d.rsapps.net with LMTP id +OhpBeBPr2GGcQAAvGGmqA (envelope-from ) for ; Tue, 07 Dec 2021 07:13:20 -0500 Received: from smtp39.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy6.mail.ord1c.rsapps.net with LMTPS id KOfrBOBPr2HCCQAA9sKXow (envelope-from ) for ; Tue, 07 Dec 2021 07:13:20 -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: smtp39.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 106c0028-5757-11ec-9615-5452006c005a-1-1 Received: from [216.105.38.7] ([216.105.38.7:46962] helo=lists.sourceforge.net) by smtp39.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id F2/F4-19324-FDF4FA16; Tue, 07 Dec 2021 07:13:19 -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.94.2) (envelope-from ) id 1muZKX-0000Av-TM; Tue, 07 Dec 2021 12:12:21 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKP-00009O-LE for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=4Bcr7sZsrbSGUYAsWizxmD7CPGquNuSE/20VpUCTwgE=; b=k3lNDk8O4yb3jcQ3ldRUE4UktY 9kFlbNIWwWpOMAYqSexldRuutvQwNdwteUQhxCeViOh6upc5IA+ubn4txzQFzw7WUGLQBigCvzYYx CNo3c/AuFTJz9Dz/7x32XMMMlVxaTR9IV4dwPNnXpOHyapQn5gu8bIvR7me9RbIsVnc0=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=4Bcr7sZsrbSGUYAsWizxmD7CPGquNuSE/20VpUCTwgE=; b=YHNxpVH+gNTaAI0Tepb3I7TYMK 3oLM5696rE3lR2oOFhZ6PvjfvXhpEW+ODUSctsv1y1hLwdWxvdHksmfvVZpujujlZCiuJmIROt1KO ymMKJaEqHrpJQ75mDf5iIkiM2Dq5bBI394Y48HwafsKnviSguHIpjbaM6ERlOQAYS4wU=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKI-007MQj-Gb for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:13 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:35 +0100 Message-Id: <20211207121137.3221-7-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Arne Schwabe Implement the data-channel offloading using the ovpn-dco-win kernel module. See README.dco.md for more details. Signed-off-by: Arne Schwabe Signed-off-by: Lev Stipakov Signed-off-by: Antonio Quartulli --- README.dco.md | 8 + config-msvc.h | 12 +- configure.ac [...] Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKI-007MQj-Gb Subject: [Openvpn-devel] [RFC 6/8] ovpn-dco-win: introduce windows data-channel offload 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 , Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Arne Schwabe Implement the data-channel offloading using the ovpn-dco-win kernel module. See README.dco.md for more details. Signed-off-by: Arne Schwabe Signed-off-by: Lev Stipakov Signed-off-by: Antonio Quartulli --- README.dco.md | 8 + config-msvc.h | 12 +- configure.ac | 82 +++++--- src/openvpn/Makefile.am | 1 + src/openvpn/dco.h | 1 + src/openvpn/init.c | 42 +++- src/openvpn/networking_windco.c | 301 ++++++++++++++++++++++++++++ src/openvpn/networking_windco.h | 47 +++++ src/openvpn/openvpn.vcxproj | 2 + src/openvpn/openvpn.vcxproj.filters | 6 + src/openvpn/options.c | 38 +++- src/openvpn/options.h | 27 ++- src/openvpn/socket.c | 125 +++++++++++- src/openvpn/socket.h | 57 +++++- src/openvpn/tun.c | 44 +++- src/openvpn/tun.h | 58 ++++-- 16 files changed, 758 insertions(+), 93 deletions(-) create mode 100644 src/openvpn/networking_windco.c create mode 100644 src/openvpn/networking_windco.h diff --git a/README.dco.md b/README.dco.md index e2500d36..8ecda129 100644 --- a/README.dco.md +++ b/README.dco.md @@ -60,6 +60,12 @@ see a message like in your log. +Getting started (Windows) +------------------------- +Getting started under windows is currently for brave people having experience +with windows development. You need to compile openvpn yourself and also need +to get the test driver installed on your system. + DCO and P2P mode ---------------- DCO is also available when running OpenVPN in P2P mode without --pull/--client option. @@ -105,6 +111,8 @@ Limitations by design - topology subnet is the only supported `--topology` for servers - iroute directives install routes on the host operating system, see also routing with ovpn-dco +- (ovpn-dco-win) client and p2p mode only +- (ovpn-dco-win) only AES-GCM-128/192/256 cipher support Current limitations ------------------- diff --git a/config-msvc.h b/config-msvc.h index 0ae38482..a1a1d555 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -6,10 +6,10 @@ #define ENABLE_CRYPTO_OPENSSL 1 #define ENABLE_FRAGMENT 1 #define ENABLE_HTTP_PROXY 1 -#define ENABLE_LZO 1 +//#define ENABLE_LZO 1 #define ENABLE_LZ4 1 #define ENABLE_MANAGEMENT 1 -#define ENABLE_PKCS11 1 +//#define ENABLE_PKCS11 0 #define ENABLE_PLUGIN 1 #define ENABLE_PORT_SHARE 1 #define ENABLE_SOCKS 1 @@ -30,8 +30,8 @@ #define HAVE_IO_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_STAT_H 1 -#define HAVE_LZO_LZO1X_H 1 -#define HAVE_LZO_LZOUTIL_H 1 +//#define HAVE_LZO_LZO1X_H 1 +//#define HAVE_LZO_LZOUTIL_H 1 #define HAVE_VERSIONHELPERS_H 1 #define HAVE_ACCESS 1 @@ -86,3 +86,7 @@ typedef uint16_t in_port_t; #ifdef HAVE_CONFIG_MSVC_LOCAL_H #include #endif + +#define ENABLE_WINDCO 1 +#define ENABLE_DCO 1 + diff --git a/configure.ac b/configure.ac index 7d05d905..b6ecb23a 100644 --- a/configure.ac +++ b/configure.ac @@ -784,41 +784,63 @@ dnl version in this tree which will be used by default. The dnl git checkout inside the ovpn-dco/ directory is managed via git dnl submodule. dnl -AC_ARG_VAR([DCO_SOURCEDIR], [Alternative ovpn-dco kernel module source directory]) -if test -z "${DCO_SOURCEDIR}"; then - DCO_SOURCEDIR="${srcdir}/../ovpn-dco" -fi -AC_MSG_NOTICE([Using ovpn-dco source directory: ${DCO_SOURCEDIR}]) -AC_SUBST([DCO_SOURCEDIR]) + AC_ARG_VAR([DCO_SOURCEDIR], [Alternative ovpn-dco kernel module source directory]) + if test -z "${DCO_SOURCEDIR}"; then + case "$host" in + *-mingw*) DCO_SOURCEDIR="${srcdir}/../ovpn-dco-win";; + *) DCO_SOURCEDIR="${srcdir}/../ovpn-dco";; + esac + fi + AC_MSG_NOTICE([Using ovpn-dco source directory: ${DCO_SOURCEDIR}]) + AC_SUBST([DCO_SOURCEDIR]) + case "$host" in + *-*-linux*) dnl dnl Include generic netlink library used to talk to ovpn-dco dnl - saved_CFLAGS="${CFLAGS}" - PKG_CHECK_MODULES( - [LIBNL_GENL], - [libnl-genl-3.0 >= 3.2.29], - [have_libnl="yes"], - [AC_MSG_ERROR([libnl-genl-3.0 package not found or too old. Is the development package and pkg-config installed? Must be version 3.4.0 or newer])] - ) - - DCO_CFLAGS="-I${DCO_SOURCEDIR}/include/uapi ${LIBNL_GENL_CFLAGS}" - - CFLAGS="${CFLAGS} ${DCO_CFLAGS}" - AC_CHECK_HEADERS( - [linux/ovpn_dco.h], - , - [AC_MSG_ERROR([linux/ovpn_dco.h is missing (use DCO_SOURCE to set path to it, CFLAGS=${CFLAGS})])] - ) - CFLAGS=${saved_CFLAGS} - OPTIONAL_DCO_CFLAGS="${DCO_CFLAGS}" - OPTIONAL_DCO_LIBS="${LIBNL_GENL_LIBS}" - - AC_DEFINE(ENABLE_LINUXDCO, 1, [Enable linux data channel offload]) - AC_DEFINE(ENABLE_DCO, 1, [Enable shared data channel offload]) -fi -AM_CONDITIONAL([ENABLE_OVPNDCO], [test "${enable_dco}" = "yes"]) + saved_CFLAGS="${CFLAGS}" + PKG_CHECK_MODULES( + [LIBNL_GENL], + [libnl-genl-3.0 >= 3.2.29], + [have_libnl="yes"], + [AC_MSG_ERROR([libnl-genl-3.0 package not found or too old. Is the development package and pkg-config installed? Must be version 3.4.0 or newer])] + ) + DCO_CFLAGS="-I${DCO_SOURCEDIR}/include/uapi ${LIBNL_GENL_CFLAGS}" + + CFLAGS="${CFLAGS} ${DCO_CFLAGS}" + AC_CHECK_HEADERS( + [linux/ovpn_dco.h], + , + [AC_MSG_ERROR([linux/ovpn_dco.h is missing (use DCO_SOURCE to set path to it, CFLAGS=${CFLAGS})])] + ) + CFLAGS=${saved_CFLAGS} + + OPTIONAL_DCO_LIBS="${LIBNL_GENL_LIBS}" + + AC_DEFINE(ENABLE_LINUXDCO, 1, [Enable linux data channel offload]) + ;; + + *-mingw*) + DCO_CFLAGS="-I${DCO_SOURCEDIR}" + + saved_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} ${DCO_CFLAGS}" + AC_CHECK_HEADERS( + [uapi/ovpn-dco.h], + , + [AC_MSG_ERROR([uapi/ovpn-dco.h is missing (use DCO_SOURCEDIR to set path to it, CFLAGS=${CFLAGS})])] + ) + CFLAGS=${saved_CFLAGS} + + AC_DEFINE(ENABLE_WINDCO, 1, [Enable shared data channel offload for Windows]) + ;; + esac + + OPTIONAL_DCO_CFLAGS="${DCO_CFLAGS}" + AC_DEFINE(ENABLE_DCO, 1, [Enable shared data channel offload]) +fi if test "${with_crypto_library}" = "openssl"; then AC_ARG_VAR([OPENSSL_CFLAGS], [C compiler flags for OpenSSL]) diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 0cc06155..9645209b 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -88,6 +88,7 @@ openvpn_SOURCES = \ networking_iproute2.c networking_iproute2.h \ networking_sitnl.c networking_sitnl.h \ networking_linuxdco.c networking_linuxdco.h \ + networking_windco.c networking_windco.h \ networking.h \ ntlm.c ntlm.h \ occ.c occ.h \ diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h index 1cfdc8fb..f0334536 100644 --- a/src/openvpn/dco.h +++ b/src/openvpn/dco.h @@ -41,6 +41,7 @@ static inline void open_tun_dco(struct tuntap *tt, const char* dev) { ASSERT(fal static inline void close_tun_dco(struct tuntap *tt) { ASSERT(false); } #else +#include "networking_windco.h" #include "networking_linuxdco.h" #include "crypto.h" diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4668fd04..6632cb7f 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1737,7 +1737,8 @@ do_init_tun(struct context *c) c->c1.link_socket_addr.remote_list, !c->options.ifconfig_nowarn, c->c2.es, - &c->net_ctx); + &c->net_ctx, + c->c1.tuntap); #ifdef _WIN32 c->c1.tuntap->windows_driver = c->options.windows_driver; @@ -1761,7 +1762,15 @@ do_open_tun(struct context *c) bool ret = false; #ifndef TARGET_ANDROID - if (!c->c1.tuntap) + if (!c->c1.tuntap +#ifdef _WIN32 + || (c->c1.tuntap +#ifdef ENABLE_WINDCO + && !c->c1.tuntap->dco.real_tun_init +#endif + ) +#endif + ) { #endif @@ -1829,9 +1838,12 @@ do_open_tun(struct context *c) /* Store the old fd inside the fd so open_tun can use it */ c->c1.tuntap->fd = oldtunfd; #endif - /* open the tun device */ - open_tun(c->options.dev, c->options.dev_type, c->options.dev_node, - c->c1.tuntap); + /* open the tun device. ovpn-dco-win already opend the device for the socket */ + if (!is_windco(c->c1.tuntap)) + { + open_tun(c->options.dev, c->options.dev_type, c->options.dev_node, + c->c1.tuntap); + } /* set the hardware address */ if (c->options.lladdr) @@ -3646,6 +3658,26 @@ do_close_free_key_schedule(struct context *c, bool free_ssl_ctx) static void do_close_link_socket(struct context *c) { +#ifdef _WIN32 + if (c->c2.link_socket && c->c2.link_socket->info.dco_installed && is_windco(c->c1.tuntap)) + { + ASSERT(c->c2.link_socket_owned); + ASSERT(c->c1.tuntap); + + /* We rely on the tun close to the handle if also setup + * routes etc, since they cannot be delete when the interface + * handle has been closed */ + if (true +#ifdef ENABLE_WINDCO + && !c->c1.tuntap->dco.real_tun_init +#endif + ) + { + do_close_tun_simple(c); + } + c->c2.link_socket->sd = SOCKET_UNDEFINED; + } +#endif if (c->c2.link_socket && c->c2.link_socket_owned) { link_socket_close(c->c2.link_socket); diff --git a/src/openvpn/networking_windco.c b/src/openvpn/networking_windco.c new file mode 100644 index 00000000..3c88b752 --- /dev/null +++ b/src/openvpn/networking_windco.c @@ -0,0 +1,301 @@ +/* + * Interface to ovpn-win-dco networking code + * + * Copyright (C) 2020 Arne Schwabe + * Copyright (C) 2020 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#if defined(ENABLE_WINDCO) +#include "syshead.h" + +#include "networking_windco.h" +#include "dco.h" +#include "tun.h" +#include "crypto.h" +#include "ssl_common.h" + + +#include +#include + +#if defined(__MINGW32__) +const IN_ADDR in4addr_any = { 0 }; +#endif + +static struct tuntap create_dco_handle(const char* devname, struct gc_arena *gc) +{ + struct tuntap tt = { 0 }; + + tt.windows_driver = WINDOWS_DRIVER_WINDCO; + + const char* device_guid; + tun_open_device(&tt, devname, &device_guid, gc); + tt.windows_driver = WINDOWS_DRIVER_WINDCO; + + return tt; +} + +void open_tun_dco(struct tuntap *tt, const char* dev) +{ + ASSERT(0); +} + +void dco_start_tun(struct tuntap* tt) +{ + msg(D_DCO_DEBUG, "%s", __func__); + + DWORD bytes_returned = 0; + if (!DeviceIoControl(tt->hand, OVPN_IOCTL_START_VPN, NULL, 0, NULL, 0, + &bytes_returned, NULL)) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_START_VPN) failed with code %lu", GetLastError()); + } +} + +int dco_connect_wait(HANDLE handle, OVERLAPPED* ov, int timeout, volatile int* signal_received) +{ + while (timeout-- > 0) + { + DWORD transferred; + if (GetOverlappedResultEx(handle, ov, &transferred, 1000, FALSE) != 0) + { + /* TCP connection established by dco */ + return 0; + } + + DWORD err = GetLastError(); + if (err != WAIT_TIMEOUT) + { + /* dco reported connection error */ + struct gc_arena gc = gc_new(); + msg(M_NONFATAL, "%s: %s", __func__, strerror_win32(err, &gc)); + *signal_received = SIGUSR1; + gc_free(&gc); + return -1; + } + + get_signal(signal_received); + if (*signal_received) + { + return -1; + } + + management_sleep(0); + } + + /* we end up here when timeout occurs in userspace */ + msg(M_NONFATAL, "%s: dco connect timeout", __func__); + *signal_received = SIGUSR1; + + return -1; +} + +struct tuntap +dco_create_socket(struct addrinfo *remoteaddr, bool bind_local, + struct addrinfo *bind, const char* devname, + struct gc_arena *gc, int timeout, volatile int* signal_received) +{ + msg(D_DCO_DEBUG, "%s", __func__); + + OVPN_NEW_PEER peer = { 0 }; + + struct sockaddr *local = NULL; + struct sockaddr *remote = remoteaddr->ai_addr; + + if (remoteaddr->ai_protocol == IPPROTO_TCP + || remoteaddr->ai_socktype == SOCK_STREAM) + { + peer.Proto = OVPN_PROTO_TCP; + } + else + { + peer.Proto = OVPN_PROTO_UDP; + } + + if (bind_local) + { + /* Use first local address with correct address family */ + while(bind && !local) + { + if (bind->ai_family == remote->sa_family) + { + local = bind->ai_addr; + } + bind = bind->ai_next; + } + } + + if (bind_local && !local) + { + msg(M_FATAL, "DCO: Socket bind failed: Address to bind lacks %s record", + addr_family_name(remote->sa_family)); + } + + if (remote->sa_family == AF_INET6) + { + peer.Remote.Addr6 = *((SOCKADDR_IN6 *)(remoteaddr->ai_addr)); + if (local) + { + peer.Local.Addr6 = *((SOCKADDR_IN6 *)local); + } + else + { + peer.Local.Addr6.sin6_addr = in6addr_any; + peer.Local.Addr6.sin6_port = 0; + peer.Local.Addr6.sin6_family = AF_INET6; + } + } + else if (remote->sa_family == AF_INET) + { + peer.Remote.Addr4 = *((SOCKADDR_IN *)(remoteaddr->ai_addr)); + if (local) + { + peer.Local.Addr4 = *((SOCKADDR_IN *)local); + } + else + { + peer.Local.Addr4.sin_addr = in4addr_any; + peer.Local.Addr4.sin_port = 0; + peer.Local.Addr4.sin_family = AF_INET; + } + } + else + { + ASSERT(0); + } + + struct tuntap tt = create_dco_handle(devname, gc); + + OVERLAPPED ov = { 0 }; + if (!DeviceIoControl(tt.hand, OVPN_IOCTL_NEW_PEER, &peer, sizeof(peer), NULL, 0, NULL, &ov)) + { + DWORD err = GetLastError(); + if (err != ERROR_IO_PENDING) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_PEER) failed with code %lu", err); + } + else + { + if (dco_connect_wait(tt.hand, &ov, timeout, signal_received)) + { + close_tun_handle(&tt); + } + } + } + return tt; +} + +int dco_new_peer(struct tuntap *tt, unsigned int peerid, int sd, + struct sockaddr *localaddr, struct sockaddr *remoteaddr, + struct in_addr *remote_in4, struct in6_addr *remote_in6) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d, fd %d", __func__, peerid, sd); + return 0; +} + +int ovpn_set_peer(struct tuntap *tt, unsigned int peerid, + unsigned int keepalive_interval, + unsigned int keepalive_timeout) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d, keepalive %d/%d", __func__, peerid, + keepalive_interval, keepalive_timeout); + + OVPN_SET_PEER peer; + + peer.KeepaliveInterval = keepalive_interval; + peer.KeepaliveTimeout = keepalive_timeout; + + DWORD bytes_returned = 0; + if (!DeviceIoControl(tt->hand, OVPN_IOCTL_SET_PEER, &peer, sizeof(peer), NULL, 0, &bytes_returned, NULL)) + { + msg(M_WARN, "DeviceIoControl(OVPN_IOCTL_SET_PEER) failed with code %lu", GetLastError()); + return -1; + } + return 0; +} + +int +dco_new_key(struct tuntap *tt, unsigned int peerid, ovpn_key_slot_t slot, + struct key_state *ks, const char* ciphername) +{ + msg(D_DCO_DEBUG, "%s: slot %d, key-id %d, peer-id %d, cipher %s", + __func__, slot, ks->key_id, peerid, ciphername); + + struct key_ctx_bi *key = &ks->crypto_options.key_ctx_bi; + dco_check_key_ctx(key); + + const int nonce_len = 8; + size_t key_len = cipher_kt_key_size(cipher_kt_get(ciphername)); + + OVPN_CRYPTO_DATA crypto_data; + ZeroMemory(&crypto_data, sizeof(crypto_data)); + + crypto_data.CipherAlg = get_dco_cipher(ciphername); + crypto_data.KeyId = ks->key_id; + crypto_data.PeerId = peerid; + crypto_data.KeySlot = slot; + + CopyMemory(crypto_data.Encrypt.Key, key->encrypt.aead_key, key_len); + crypto_data.Encrypt.KeyLen = (char)key_len; + CopyMemory(crypto_data.Encrypt.NonceTail, key->encrypt.implicit_iv, nonce_len); + + CopyMemory(crypto_data.Decrypt.Key, key->decrypt.aead_key, key_len); + crypto_data.Decrypt.KeyLen = (char)key_len; + CopyMemory(crypto_data.Decrypt.NonceTail, key->decrypt.implicit_iv, nonce_len); + + ASSERT(crypto_data.CipherAlg > 0); + + DWORD bytes_returned = 0; + + secure_memzero(key->encrypt.aead_key, sizeof (key->encrypt.aead_key)); + secure_memzero(key->decrypt.aead_key, sizeof (key->decrypt.aead_key)); + + if (!DeviceIoControl(tt->hand, OVPN_IOCTL_NEW_KEY, &crypto_data, sizeof(crypto_data), NULL, 0, + &bytes_returned, NULL)) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_NEW_KEY) failed with code %lu", GetLastError()); + return -1; + } + return 0; +} +int +dco_del_key(struct tuntap *tt, unsigned int peerid, ovpn_key_slot_t slot) +{ + msg(D_DCO, "%s: peer-id %d, slot %d called but ignored", __func__, peerid, slot); + /* FIXME: Implement in driver first */ + return 0; +} + +int dco_swap_keys(struct tuntap *tt, unsigned int peer_id) +{ + msg(D_DCO_DEBUG, "%s: peer-id %d", __func__, peer_id); + + DWORD bytes_returned = 0; + if (!DeviceIoControl(tt->hand, OVPN_IOCTL_SWAP_KEYS, NULL, 0, NULL, 0, + &bytes_returned, NULL)) + { + msg(M_ERR, "DeviceIoControl(OVPN_IOCTL_SWAP_KEYS) failed with code %lu", GetLastError()); + } + return 0; +} +#endif \ No newline at end of file diff --git a/src/openvpn/networking_windco.h b/src/openvpn/networking_windco.h new file mode 100644 index 00000000..e48aaa6c --- /dev/null +++ b/src/openvpn/networking_windco.h @@ -0,0 +1,47 @@ +/* + * Interface to ovpn-win-dco networking code + * + * Copyright (C) 2020 Arne Schwabe + * Copyright (C) 2020 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OPENVPN_NETWORKING_WINDCO_H +#define OPENVPN_NETWORKING_WINDCO_H +#if defined(ENABLE_WINDCO) +#include "uapi/ovpn-dco.h" +#include "buffer.h" + + +typedef OVPN_KEY_SLOT ovpn_key_slot_t; + +#define DCO_SUPPORTED_CIPHERS "AES-128-GCM:AES-256-GCM:AES-192-GCM" + +struct dco_context { + bool real_tun_init; +}; + +struct tuntap +dco_create_socket(struct addrinfo *remoteaddr, bool bind_local, + struct addrinfo *bind, const char* devname, + struct gc_arena *gc, int timeout, volatile int* signal_received); + +void dco_start_tun(struct tuntap* tt); + +typedef struct dco_context dco_context_t; + +#endif +#endif //OPENVPN_NETWORKING_WINDCO_H diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index b394cd4a..1258b633 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -279,6 +279,7 @@ + @@ -365,6 +366,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index abb591e4..402999b1 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -249,6 +249,9 @@ Source Files + + Source Files + @@ -374,6 +377,9 @@ Header Files + + Header Files + Header Files diff --git a/src/openvpn/options.c b/src/openvpn/options.c index a3014415..70c5995e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2249,6 +2249,11 @@ options_postprocess_verify_ce(const struct options *options, { msg(M_USAGE, "--windows-driver wintun requires --dev tun"); } + + if (options->windows_driver == WINDOWS_DRIVER_WINDCO) + { + check_option_conflict_dco(M_USAGE, options); + } #endif /* ifdef _WIN32 */ /* @@ -3001,8 +3006,8 @@ options_postprocess_mutate_invariant(struct options *options) #ifdef _WIN32 const int dev = dev_type_enum(options->dev, options->dev_type); - /* when using wintun, kernel doesn't send DHCP requests, so don't use it */ - if (options->windows_driver == WINDOWS_DRIVER_WINTUN + /* when using wintun/ovpn-dco-win, kernel doesn't send DHCP requests, so don't use it */ + if ((options->windows_driver == WINDOWS_DRIVER_WINTUN || options->windows_driver == WINDOWS_DRIVER_WINDCO) && (options->tuntap_options.ip_win32_type == IPW32_SET_DHCP_MASQ || options->tuntap_options.ip_win32_type == IPW32_SET_ADAPTIVE)) { options->tuntap_options.ip_win32_type = IPW32_SET_NETSH; @@ -3088,7 +3093,7 @@ options_postprocess_setdefault_ncpciphers(struct options *o) /* custom --data-ciphers set, keep list */ return; } - else if (cipher_kt_get("CHACHA20-POLY1305")) + else if (cipher_kt_get("CHACHA20-POLY1305") && !dco_win_enabled(o)) { o->ncp_ciphers = "AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305"; } @@ -3260,6 +3265,22 @@ static bool check_option_conflict_dco_platform(int msglevel, const struct option } return false; } +#elif defined(ENABLE_WINDCO) +static bool check_option_conflict_dco_platform(int msglevel, const struct options *o) +{ + if (o->mode == MODE_SERVER) + { + msg(msglevel, "Only client and p2p data channel offload is supported " + "with ovpn-dco-win."); + return true; + } + if (o->persist_tun) + { + msg(msglevel, "--persist-tun is not supported with ovpn-dco-win."); + return true; + } + return false; +} #endif bool check_option_conflict_dco(int msglevel, const struct options *o) @@ -4050,7 +4071,8 @@ options_string(const struct options *o, NULL, false, NULL, - ctx); + ctx, + NULL); if (tt) { tt_local = true; @@ -4472,9 +4494,15 @@ parse_windows_driver(const char *str, const int msglevel) { return WINDOWS_DRIVER_WINTUN; } + + else if (streq(str, "ovpn-dco-win")) + { + return WINDOWS_DRIVER_WINDCO; + } else { - msg(msglevel, "--windows-driver must be tap-windows6 or wintun"); + msg(msglevel, "--windows-driver must be tap-windows6, wintun " + "or ovpn-dco-win"); return WINDOWS_DRIVER_UNSPECIFIED; } } diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 0affc71f..321a89a5 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -865,10 +865,30 @@ void options_string_import(struct options *options, /** * Returns whether the current configuration has dco enabled. */ -#ifdef ENABLE_LINUXDCO +#if defined(ENABLE_LINUXDCO) static inline bool dco_enabled(struct options *o) { return !o->tuntap_options.disable_dco; } +#elif defined(ENABLE_WINDCO) +static inline bool dco_enabled(struct options *o) +{ + return o->windows_driver == WINDOWS_DRIVER_WINDCO; +} +#else +/* Dummy functions to avoid ifdefs in the other code */ +static inline bool +dco_enabled(struct options *o) { return false; } +#endif + +#if defined(ENABLE_WINDCO) +static inline bool +dco_win_enabled(struct options *o) { return dco_enabled(o); } +#else +static inline bool +dco_win_enabled(struct options *o) { return false; } +#endif + +#if defined(ENABLE_DCO) /** * Checks whether the options struct has any option that is not supported by * our current dco implementation. If so it prints a warning at warning level @@ -880,11 +900,6 @@ dco_enabled(struct options *o) { return !o->tuntap_options.disable_dco; } bool check_option_conflict_dco(int msglevel, const struct options *o); #else -/* Dummy functions to avoid ifdefs in the other code */ - -static inline bool -dco_enabled(struct options *o) { return false; } - static inline bool check_option_conflict_dco(int msglevel, struct options *o) { return false; } #endif diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 72062cd0..700fc2aa 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2141,6 +2141,38 @@ phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info) resolve_remote(sock, 1, NULL, &sig_info->signal_received); } +#if defined(ENABLE_WINDCO) +static void +create_socket_windco(struct context* c, struct link_socket* sock, volatile int* signal_received) +{ + struct tuntap* tt; + /* In this case persist-tun is enabled, which we don't support yet */ + ASSERT(!c->c1.tuntap); + + ALLOC_OBJ(tt, struct tuntap); + + *tt = dco_create_socket(sock->info.lsa->current_remote, + sock->bind_local, + sock->info.lsa->bind_local, + c->options.dev_node, + &c->gc, + get_server_poll_remaining_time(sock->server_poll_timeout), + signal_received); + if (*signal_received) + { + goto done; + } + c->c1.tuntap = tt; + sock->info.dco_installed = true; + + /* Ensure we can "safely" cast the handle to a socket */ + static_assert(sizeof(sock->sd) == sizeof(tt->hand), "HANDLE and SOCKET size differs"); + sock->sd = (SOCKET)tt->hand; +done: + ; +} +#endif + /* finalize socket initialization */ void link_socket_init_phase2(struct context *c) @@ -2180,7 +2212,24 @@ link_socket_init_phase2(struct context *c) /* If a valid remote has been found, create the socket with its addrinfo */ if (sock->info.lsa->current_remote) { - create_socket(sock, sock->info.lsa->current_remote); +#if defined(ENABLE_WINDCO) + if (dco_win_enabled(&c->options)) + { + create_socket_windco(c, sock, &sig_info->signal_received); + if (sig_info->signal_received) + { + goto done; + } + + linksock_print_addr(sock); + goto done; + } + else +#endif + { + create_socket(sock, sock->info.lsa->current_remote); + } + } /* If socket has not already been created create it now */ @@ -2243,6 +2292,7 @@ link_socket_init_phase2(struct context *c) } phase2_set_socket_flags(sock); + linksock_print_addr(sock); done: @@ -3199,7 +3249,14 @@ link_socket_read_tcp(struct link_socket *sock, if (!sock->stream_buf.residual_fully_formed) { #ifdef _WIN32 - len = socket_finalize(sock->sd, &sock->reads, buf, NULL); + if (sock->info.dco_installed) + { + len = tun_finalize((HANDLE)sock->sd, &sock->reads, buf); + } + else + { + len = socket_finalize(sock->sd, &sock->reads, buf, NULL); + } #else struct buffer frag; stream_buf_get_next(&sock->stream_buf, &frag); @@ -3355,7 +3412,14 @@ link_socket_write_tcp(struct link_socket *sock, len = htonps(len); ASSERT(buf_write_prepend(buf, &len, sizeof(len))); #ifdef _WIN32 - return link_socket_write_win32(sock, buf, to); + if (sock->info.dco_installed) + { + return link_socket_write_win32_dco(sock, buf, to); + } + else + { + return link_socket_write_win32(sock, buf, to); + } #else return link_socket_write_tcp_posix(sock, buf, to); #endif @@ -3478,8 +3542,20 @@ socket_recv_queue(struct link_socket *sock, int maxsize) /* the overlapped read will signal this event on I/O completion */ ASSERT(ResetEvent(sock->reads.overlapped.hEvent)); sock->reads.flags = 0; - - if (proto_is_udp(sock->info.proto)) + + if (sock->info.dco_installed) + { + status = ReadFile( + (HANDLE) sock->sd, + wsabuf[0].buf, + wsabuf[0].len, + &sock->reads.size, + &sock->reads.overlapped + ); + /* Readfile status is inverted from WSARecv */ + status = !status; + } + else if (proto_is_udp(sock->info.proto)) { sock->reads.addr_defined = true; sock->reads.addrlen = sizeof(sock->reads.addr6); @@ -3532,7 +3608,14 @@ socket_recv_queue(struct link_socket *sock, int maxsize) } else { - status = WSAGetLastError(); + if (sock->info.dco_installed) + { + status = GetLastError(); + } + else + { + status = WSAGetLastError(); + } if (status == WSA_IO_PENDING) /* operation queued? */ { sock->reads.iostate = IOSTATE_QUEUED; @@ -3577,7 +3660,21 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin ASSERT(ResetEvent(sock->writes.overlapped.hEvent)); sock->writes.flags = 0; - if (proto_is_udp(sock->info.proto)) + if (sock->info.dco_installed) + { + status = WriteFile( + (HANDLE)sock->sd, + wsabuf[0].buf, + wsabuf[0].len, + &sock->writes.size, + &sock->writes.overlapped + ); + + /* WriteFile status is inverted from WSASendTo */ + status = !status; + + } + else if (proto_is_udp(sock->info.proto)) { /* set destination address for UDP writes */ sock->writes.addr_defined = true; @@ -3638,8 +3735,17 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin } else { - status = WSAGetLastError(); - if (status == WSA_IO_PENDING) /* operation queued? */ + if (sock->info.dco_installed) + { + status = GetLastError(); + } + else + { + status = WSAGetLastError(); + } + + /* both status code have the identical value */ + if (status == WSA_IO_PENDING || status == ERROR_IO_PENDING) /* operation queued? */ { sock->writes.iostate = IOSTATE_QUEUED; sock->writes.status = status; @@ -3664,6 +3770,7 @@ socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct lin return sock->writes.iostate; } +/* Returns the nubmer of bytes successfully read */ int socket_finalize(SOCKET s, struct overlapped_io *io, diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 57142f4e..f9f5faf4 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -34,6 +34,7 @@ #include "proxy.h" #include "socks.h" #include "misc.h" +#include "tun.h" /* * OpenVPN's default port number as assigned by IANA. @@ -1021,7 +1022,17 @@ link_socket_read_udp_win32(struct link_socket *sock, struct buffer *buf, struct link_socket_actual *from) { - return socket_finalize(sock->sd, &sock->reads, buf, from); + if (sock->info.dco_installed) + { + /* from address was set on socket creation and the kernel + * checks that it matches for us */ + addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest); + return tun_finalize((HANDLE)sock->sd, &sock->reads, buf); + } + else + { + return socket_finalize(sock->sd, &sock->reads, buf, from); + } } #else /* ifdef _WIN32 */ @@ -1038,7 +1049,10 @@ link_socket_read(struct link_socket *sock, struct buffer *buf, struct link_socket_actual *from) { - if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ + if (proto_is_udp(sock->info.proto) + || sock->info.dco_installed) + /* unified UDPv4 and UDPv6, for DCO the kernel + * will strip the length header */ { int res; @@ -1082,10 +1096,6 @@ link_socket_write_win32(struct link_socket *sock, if (overlapped_io_active(&sock->writes)) { status = socket_finalize(sock->sd, &sock->writes, NULL, NULL); - if (status < 0) - { - err = WSAGetLastError(); - } } socket_send_queue(sock, buf, to); if (status < 0) @@ -1099,6 +1109,29 @@ link_socket_write_win32(struct link_socket *sock, } } +static inline int +link_socket_write_win32_dco(struct link_socket* sock, + struct buffer* buf, + struct link_socket_actual* to) +{ + int err = 0; + int status = 0; + if (overlapped_io_active(&sock->writes)) + { + status = tun_finalize((HANDLE)sock->sd, &sock->writes, NULL); + } + socket_send_queue(sock, buf, to); + if (status < 0) + { + SetLastError(err); + return status; + } + else + { + return BLEN(buf); + } +} + #else /* ifdef _WIN32 */ size_t link_socket_write_udp_posix_sendmsg(struct link_socket *sock, @@ -1140,7 +1173,14 @@ link_socket_write_udp(struct link_socket *sock, struct link_socket_actual *to) { #ifdef _WIN32 - return link_socket_write_win32(sock, buf, to); + if (sock->info.dco_installed) + { + return link_socket_write_win32_dco(sock, buf, to); + } + else + { + return link_socket_write_win32(sock, buf, to); + } #else return link_socket_write_udp_posix(sock, buf, to); #endif @@ -1152,8 +1192,9 @@ link_socket_write(struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) { - if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ + if (proto_is_udp(sock->info.proto) || sock->info.dco_installed) { + /* unified UDPv4 and UDPv6 and DCO (kernel adds size header) */ return link_socket_write_udp(sock, buf, to); } else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index d8634ebf..459b20f8 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -742,13 +742,23 @@ init_tun(const char *dev, /* --dev option */ struct addrinfo *remote_public, const bool strict_warn, struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + struct tuntap *tt) { struct gc_arena gc = gc_new(); - struct tuntap *tt; - ALLOC_OBJ(tt, struct tuntap); - clear_tuntap(tt); + if (!tt) + { + ALLOC_OBJ(tt, struct tuntap); + clear_tuntap(tt); + } +#ifdef ENABLE_WINDCO + else + { + ASSERT(!tt->dco.real_tun_init); + tt->dco.real_tun_init = true; + } +#endif tt->type = dev_type_enum(dev, dev_type); tt->topology = topology; @@ -891,6 +901,13 @@ init_tun_post(struct tuntap *tt, { tt->options = *options; #ifdef _WIN32 +#ifdef ENABLED_WINDCO + if (tt->windows_driver == WINDOWS_DRIVER_WINDCO) + { + dco_start_tun(tt); + return; + } +#endif overlapped_io_init(&tt->reads, frame, FALSE, true); overlapped_io_init(&tt->writes, frame, TRUE, true); tt->adapter_index = TUN_ADAPTER_INDEX_INVALID; @@ -3438,6 +3455,9 @@ print_windows_driver(enum windows_driver_type windows_driver) case WINDOWS_DRIVER_WINTUN: return "wintun"; + + case WINDOWS_DRIVER_WINDCO: + return "ovpn-dco-win"; default: return "unspecified"; @@ -3878,6 +3898,11 @@ get_tap_reg(struct gc_arena *gc) { windows_driver = WINDOWS_DRIVER_WINTUN; } + else if (strcasecmp(component_id, "ovpn-dco") == 0) + { + windows_driver = WINDOWS_DRIVER_WINDCO; + } + if (windows_driver != WINDOWS_DRIVER_UNSPECIFIED) { @@ -4232,7 +4257,9 @@ at_least_one_tap_win(const struct tap_reg *tap_reg) { if (!tap_reg) { - msg(M_FATAL, "There are no TAP-Windows nor Wintun adapters on this system. You should be able to create an adapter by using tapctl.exe utility."); + msg(M_FATAL, "There are no TAP-Windows, Wintun or ovpn-dco-win adapters " + "on this system. You should be able to create an adapter " + "by using tapctl.exe utility."); } } @@ -6433,7 +6460,7 @@ tun_try_open_device(struct tuntap *tt, const char *device_guid, const struct dev const char *path = NULL; char tuntap_device_path[256]; - if (tt->windows_driver == WINDOWS_DRIVER_WINTUN) + if (tt->windows_driver == WINDOWS_DRIVER_WINTUN || tt->windows_driver == WINDOWS_DRIVER_WINDCO) { const struct device_instance_id_interface *dev_if; @@ -6453,7 +6480,7 @@ tun_try_open_device(struct tuntap *tt, const char *device_guid, const struct dev } else { - /* Open TAP-Windows adapter */ + /* Open TAP-Windows or dco-win adapter */ openvpn_snprintf(tuntap_device_path, sizeof(tuntap_device_path), "%s%s%s", USERMODEDEVICEDIR, device_guid, @@ -6489,7 +6516,7 @@ tun_try_open_device(struct tuntap *tt, const char *device_guid, const struct dev return true; } -static void +void tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid, struct gc_arena *gc) { const struct tap_reg *tap_reg = get_tap_reg(gc); @@ -6780,7 +6807,6 @@ netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc argv_free(&argv); } -static void close_tun_handle(struct tuntap* tt) { const char* adaptertype = print_windows_driver(tt->windows_driver); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index d5beb11c..8d3bae47 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -40,7 +40,7 @@ #include "misc.h" #include "networking.h" #include "ring_buffer.h" -#include "networking_linuxdco.h" +#include "dco.h" #ifdef _WIN32 #define WINTUN_COMPONENT_ID "wintun" @@ -48,7 +48,8 @@ enum windows_driver_type { WINDOWS_DRIVER_UNSPECIFIED, WINDOWS_DRIVER_TAP_WINDOWS6, - WINDOWS_DRIVER_WINTUN + WINDOWS_DRIVER_WINTUN, + WINDOWS_DRIVER_WINDCO }; #endif @@ -64,6 +65,8 @@ struct tuntap_options { /* --ip-win32 options */ bool ip_win32_defined; + bool disable_dco; + #define IPW32_SET_MANUAL 0 /* "--ip-win32 manual" */ #define IPW32_SET_NETSH 1 /* "--ip-win32 netsh" */ #define IPW32_SET_IPAPI 2 /* "--ip-win32 ipapi" */ @@ -246,6 +249,10 @@ tuntap_ring_empty(struct tuntap *tt) { return tuntap_is_wintun(tt) && (tt->wintun_send_ring->head == tt->wintun_send_ring->tail); } + +/* Low level function to open tun handle, used by DCO to create a handle for DCO*/ +void +tun_open_device(struct tuntap* tt, const char* dev_node, const char** device_guid, struct gc_arena* gc); #endif /* @@ -257,6 +264,8 @@ void open_tun(const char *dev, const char *dev_type, const char *dev_node, void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx); +void close_tun_handle(struct tuntap* tt); + int write_tun(struct tuntap *tt, uint8_t *buf, int len); int read_tun(struct tuntap *tt, uint8_t *buf, int len); @@ -283,7 +292,8 @@ struct tuntap *init_tun(const char *dev, /* --dev option */ struct addrinfo *remote_public, const bool strict_warn, struct env_set *es, - openvpn_net_ctx_t *ctx); + openvpn_net_ctx_t *ctx, + struct tuntap *tt); void init_tun_post(struct tuntap *tt, const struct frame *frame, @@ -659,6 +669,11 @@ write_tun_buffered(struct tuntap *tt, struct buffer *buf) } } +static inline bool is_windco(struct tuntap *tt) +{ + return tt->windows_driver == WINDOWS_DRIVER_WINDCO; +} + #else /* ifdef _WIN32 */ static inline bool @@ -684,6 +699,12 @@ tun_standby(struct tuntap *tt) return true; } + +static inline bool is_windco(struct tuntap *tt) +{ + return false; +} + #endif /* ifdef _WIN32 */ /* @@ -707,25 +728,28 @@ tun_set(struct tuntap *tt, void *arg, unsigned int *persistent) { - if (tuntap_defined(tt)) + if (!tuntap_defined(tt) || is_windco(tt)) { - /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ - if (!persistent || *persistent != rwflags) + return; + } + + /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ + if (!persistent || *persistent != rwflags) + { + event_ctl(es, tun_event_handle(tt), rwflags, arg); + if (persistent) { - event_ctl(es, tun_event_handle(tt), rwflags, arg); - if (persistent) - { - *persistent = rwflags; - } + *persistent = rwflags; } + } #ifdef _WIN32 - if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6 && (rwflags & EVENT_READ)) - { - tun_read_queue(tt, 0); - } -#endif - tt->rwflags_debug = rwflags; + if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6 && (rwflags & EVENT_READ)) + { + tun_read_queue(tt, 0); } +#endif + tt->rwflags_debug = rwflags; + } const char *tun_stat(const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc); From patchwork Tue Dec 7 01:11:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2117 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.27.255.51]) by backend41.mail.ord1d.rsapps.net with LMTP id YBgQGNxPr2EoLgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:16 -0500 Received: from proxy20.mail.iad3a.rsapps.net ([172.27.255.51]) by director9.mail.ord1d.rsapps.net with LMTP id gO+uJ9xPr2ELXQAAalYnBA (envelope-from ) for ; Tue, 07 Dec 2021 07:13:16 -0500 Received: from smtp6.gate.iad3a ([172.27.255.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy20.mail.iad3a.rsapps.net with LMTPS id iHqXH9xPr2HKVgAAtfLT2w (envelope-from ) for ; Tue, 07 Dec 2021 07:13:16 -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.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 0e5919a6-5757-11ec-9431-5254002f0085-1-1 Received: from [216.105.38.7] ([216.105.38.7:53824] helo=lists.sourceforge.net) by smtp6.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 99/F1-21140-CDF4FA16; Tue, 07 Dec 2021 07:13:16 -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.94.2) (envelope-from ) id 1muZKP-00009P-N0; Tue, 07 Dec 2021 12:12:13 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKN-000096-8C for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=dRj5pe45Slsye9AapTy8UUudUWB3h68mEWtz2mk3S5Q=; b=YqDGv9icphGo8qkxGwP5+Ly/DY W4lLFmzfkc8Mmc4VkaWmsRD7ICWoizx+Clvlb0s6LeN8DSaCOlPYWXXm7SU1f1NO+d5yk/orMNCjN ghNeqLFEceX/VbkIlwAk0yx1RRZvO6JyfO/gVHt+Dpl/zEcybz9QE94tVuGMVpclQDVY=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=dRj5pe45Slsye9AapTy8UUudUWB3h68mEWtz2mk3S5Q=; b=VUjU2IxppOJrerCgS4J+Mi+gEk Vsu54MO5Ag6vG0wiz/waUHdCRNkAAiOVLfoRVFryHRKKhrrj+Qu/+qW3LdZ05abOgWXN6zoKv42nt uD5pmOUp8ggd/ZYVsbe0mGN7EtMvk07SpofmkVseUTk6RrWtzsFoNJL4XwNQHP9d46i8=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKJ-0008PI-8t for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:10 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:36 +0100 Message-Id: <20211207121137.3221-8-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Lev Stipakov mingw i686 has GetOverlappedResultEx() in header file but not in lib file, causing linking error. To work around this issue, introduce dco_get_overlapped_result compat macro, which is defined as GetOverlappedResultEx() for all build configurations except mingw i686. For latter case, define compat [...] Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKJ-0008PI-8t Subject: [Openvpn-devel] [RFC 7/8] ovpn-dco-win: fix mingw i686 build 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 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Lev Stipakov mingw i686 has GetOverlappedResultEx() in header file but not in lib file, causing linking error. To work around this issue, introduce dco_get_overlapped_result compat macro, which is defined as GetOverlappedResultEx() for all build configurations except mingw i686. For latter case, define compat implementation which uses GetOverlappedResult() and Sleep(). Signed-off-by: Lev Stipakov Signed-off-by: Arne Schwabe --- src/compat/Makefile.am | 3 +- src/compat/compat-dco_get_overlapped_result.c | 44 +++++++++++++++++++ src/compat/compat.h | 6 +++ src/compat/compat.vcxproj | 1 + src/compat/compat.vcxproj.filters | 3 ++ src/openvpn/networking_windco.c | 11 +++-- 6 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/compat/compat-dco_get_overlapped_result.c diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am index 95eb04bb..cefc2d81 100644 --- a/src/compat/Makefile.am +++ b/src/compat/Makefile.am @@ -28,4 +28,5 @@ libcompat_la_SOURCES = \ compat-gettimeofday.c \ compat-daemon.c \ compat-strsep.c \ - compat-versionhelpers.h + compat-versionhelpers.h \ + compat-dco_get_overlapped_result.c diff --git a/src/compat/compat-dco_get_overlapped_result.c b/src/compat/compat-dco_get_overlapped_result.c new file mode 100644 index 00000000..4a52dd46 --- /dev/null +++ b/src/compat/compat-dco_get_overlapped_result.c @@ -0,0 +1,44 @@ +/* + * 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) 2021 Lev Stipakov + * Copyright (C) 2021 OpenVPN Inc + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "compat.h" + +#if defined(__MINGW32__) && !defined(__MINGW64__) +BOOL dco_get_overlapped_result(HANDLE handle, OVERLAPPED* ov, DWORD* transferred, DWORD delay_millisec, BOOL unused) +{ + BOOL res = GetOverlappedResult(handle, ov, transferred, FALSE); + if ((res == 0) && (GetLastError() == ERROR_IO_INCOMPLETE)) + { + Sleep(delay_millisec); + } + return res; +} +#endif diff --git a/src/compat/compat.h b/src/compat/compat.h index 026974a8..274febce 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -62,4 +62,10 @@ char *strsep(char **stringp, const char *delim); #endif +#if defined(__MINGW32__) && !defined(__MINGW64__) +BOOL dco_get_overlapped_result(HANDLE handle, OVERLAPPED* ov, DWORD* transferred, DWORD delay_millisec, BOOL unused); +#else +#define dco_get_overlapped_result GetOverlappedResultEx +#endif + #endif /* COMPAT_H */ diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj index fe03a51a..1dacb503 100644 --- a/src/compat/compat.vcxproj +++ b/src/compat/compat.vcxproj @@ -159,6 +159,7 @@ + diff --git a/src/compat/compat.vcxproj.filters b/src/compat/compat.vcxproj.filters index 96ca026a..73fc9f91 100644 --- a/src/compat/compat.vcxproj.filters +++ b/src/compat/compat.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + diff --git a/src/openvpn/networking_windco.c b/src/openvpn/networking_windco.c index 3c88b752..f4ec01bc 100644 --- a/src/openvpn/networking_windco.c +++ b/src/openvpn/networking_windco.c @@ -74,17 +74,22 @@ void dco_start_tun(struct tuntap* tt) int dco_connect_wait(HANDLE handle, OVERLAPPED* ov, int timeout, volatile int* signal_received) { - while (timeout-- > 0) + DWORD timeout_msec = timeout * 1000; + const int poll_interval_ms = 50; + + while (timeout_msec > 0) { + timeout_msec -= poll_interval_ms; + DWORD transferred; - if (GetOverlappedResultEx(handle, ov, &transferred, 1000, FALSE) != 0) + if (dco_get_overlapped_result(handle, ov, &transferred, poll_interval_ms, FALSE) != 0) { /* TCP connection established by dco */ return 0; } DWORD err = GetLastError(); - if (err != WAIT_TIMEOUT) + if ((err != WAIT_TIMEOUT) && (err != ERROR_IO_INCOMPLETE)) { /* dco reported connection error */ struct gc_arena gc = gc_new(); From patchwork Tue Dec 7 01:11:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 2116 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id CHPAKNtPr2E1LgAAqwncew (envelope-from ) for ; Tue, 07 Dec 2021 07:13:15 -0500 Received: from proxy13.mail.ord1d.rsapps.net ([172.30.191.6]) by director12.mail.ord1d.rsapps.net with LMTP id GKMiDttPr2ENUAAAIasKDg (envelope-from ) for ; Tue, 07 Dec 2021 07:13:15 -0500 Received: from smtp19.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy13.mail.ord1d.rsapps.net with LMTPS id eDzwN9tPr2GKHgAAgjf6aA (envelope-from ) for ; Tue, 07 Dec 2021 07:13: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: smtp19.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; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 0e1ff7c0-5757-11ec-a177-bc305bf036e4-1-1 Received: from [216.105.38.7] ([216.105.38.7:46922] helo=lists.sourceforge.net) by smtp19.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id DE/89-16381-BDF4FA16; Tue, 07 Dec 2021 07:13: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.94.2) (envelope-from ) id 1muZKZ-0000BN-Fk; Tue, 07 Dec 2021 12:12:23 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1muZKQ-00009f-4a for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:14 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=q1meHo+xgARp+dbbCj9e9m5wrKT17jIMdmTPSEOX2Ys=; b=HASDm9RmTeN3G+4LtKE6X3kt8R sOpDusLKbcIkqhhZIG+5RSr5ekyedjNcEsRbwcK4eswBER+GGJjnOctkQGy219cMPvCd9THeWD37x wIM8z/xGIxSID+22yUgaevjrjRcGWKVfEvGMxCpKpBVOB7e+WETqZ7w8EvdliZliuwvA=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=q1meHo+xgARp+dbbCj9e9m5wrKT17jIMdmTPSEOX2Ys=; b=jIwhISa0Am+yMQh8A8ttOgCdf9 ip6IWAFRHmgxAVw5K7gVhFONeiLT7aXfTQzJLIzIbIrNO7MmjBBqjFwN1ddr9wH8WtqCtU86PlStJ JhooFQbWqZbjgUyBbmhhvO80fMoPd2bnG//5px/F/FGx34ZLu1wo0haqd/XE1emGoxaY=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) id 1muZKM-007MR3-PE for openvpn-devel@lists.sourceforge.net; Tue, 07 Dec 2021 12:12:13 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 7 Dec 2021 13:11:37 +0100 Message-Id: <20211207121137.3221-9-a@unstable.cc> In-Reply-To: <20211207121137.3221-1-a@unstable.cc> References: <20211207121137.3221-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Signed-off-by: Antonio Quartulli --- configure.ac | 32 ++++++++++ 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index b6ecb23a..1911f24e 100644 --- a/configure.ac +++ b/configure.ac @@ -777,29 +777,22 @@ PKG_CHECK_MODULES( Content analysis details: (0.0 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1muZKM-007MR3-PE Subject: [Openvpn-devel] [RFC 8/8] ovpn-dco: force user to set DCO_INCLUDEDIR 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: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Signed-off-by: Antonio Quartulli --- configure.ac | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index b6ecb23a..1911f24e 100644 --- a/configure.ac +++ b/configure.ac @@ -777,29 +777,22 @@ PKG_CHECK_MODULES( if test "$enable_dco" = "yes"; then dnl -dnl Configure path for the ovpn-dco kernel module source directory. +dnl Configure path for the ovpn-dco header directory. dnl -dnl This is similar to the core librariy, there is an embedded -dnl version in this tree which will be used by default. The -dnl git checkout inside the ovpn-dco/ directory is managed via git -dnl submodule. -dnl - AC_ARG_VAR([DCO_SOURCEDIR], [Alternative ovpn-dco kernel module source directory]) - if test -z "${DCO_SOURCEDIR}"; then - case "$host" in - *-mingw*) DCO_SOURCEDIR="${srcdir}/../ovpn-dco-win";; - *) DCO_SOURCEDIR="${srcdir}/../ovpn-dco";; - esac + AC_ARG_VAR([DCO_INCLUDEDIR], [ovpn-dco header directory (where to find ovpn-dco.h)]) + if test -z "${DCO_INCLUDEDIR}"; then + AC_MSG_ERROR([You must specify DCO_INCLUDEDIR when using --enable-dco.]) + fi - AC_MSG_NOTICE([Using ovpn-dco source directory: ${DCO_SOURCEDIR}]) - AC_SUBST([DCO_SOURCEDIR]) + + AC_MSG_NOTICE([Using ovpn-dco header directory: ${DCO_INCLUDEDIR}]) + DCO_CFLAGS="-I${DCO_INCLUDEDIR}" case "$host" in *-*-linux*) dnl dnl Include generic netlink library used to talk to ovpn-dco dnl - saved_CFLAGS="${CFLAGS}" PKG_CHECK_MODULES( [LIBNL_GENL], [libnl-genl-3.0 >= 3.2.29], @@ -807,16 +800,12 @@ dnl [AC_MSG_ERROR([libnl-genl-3.0 package not found or too old. Is the development package and pkg-config installed? Must be version 3.4.0 or newer])] ) - DCO_CFLAGS="-I${DCO_SOURCEDIR}/include/uapi ${LIBNL_GENL_CFLAGS}" - - CFLAGS="${CFLAGS} ${DCO_CFLAGS}" + CFLAGS="${CFLAGS} ${DCO_CFLAGS} ${LIBNL_GENL_CFLAGS}" AC_CHECK_HEADERS( [linux/ovpn_dco.h], , - [AC_MSG_ERROR([linux/ovpn_dco.h is missing (use DCO_SOURCE to set path to it, CFLAGS=${CFLAGS})])] + [AC_MSG_ERROR([linux/ovpn_dco.h couldn't be found (use DCO_INCLUDEDIR to set the path to it, CFLAGS=${CFLAGS})])] ) - CFLAGS=${saved_CFLAGS} - OPTIONAL_DCO_LIBS="${LIBNL_GENL_LIBS}" AC_DEFINE(ENABLE_LINUXDCO, 1, [Enable linux data channel offload]) @@ -1407,7 +1396,6 @@ AC_SUBST([OPTIONAL_PKCS11_HELPER_CFLAGS]) AC_SUBST([OPTIONAL_PKCS11_HELPER_LIBS]) AC_SUBST([OPTIONAL_INOTIFY_CFLAGS]) AC_SUBST([OPTIONAL_INOTIFY_LIBS]) -AC_SUBST([OPTIONAL_DCO_CFLAGS]) AC_SUBST([OPTIONAL_DCO_LIBS]) AC_SUBST([PLUGIN_AUTH_PAM_CFLAGS])