From patchwork Tue Jul 30 09:24:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "plaisthos (Code Review)" X-Patchwork-Id: 3779 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:bb85:b0:5a1:d4fc:4ac6 with SMTP id gl5csp105666mab; Tue, 30 Jul 2024 02:25:32 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWuV9L3esnnOsre7n99tXBsUUzOO4boAQw71OIQAxyDy1JYqfXJEF3ZveQbPAb5XywEO5HfHvibvUQ=@openvpn.net X-Google-Smtp-Source: AGHT+IG6XUwzz+Jh7l4YPrBvevxACAWoaKIIWQ05gc2LiobjRNV1mMkIvYMJox+ECDDnRr6eyp1K X-Received: by 2002:a05:6a21:329e:b0:1c4:c4cc:fa49 with SMTP id adf61e73a8af0-1c4c4cd043bmr4983544637.7.1722331531613; Tue, 30 Jul 2024 02:25:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1722331531; cv=none; d=google.com; s=arc-20160816; b=l0M+qcm3YcDo0xRHPYEPFi5xjkfPh6OP9Iritg4Dv8WFHPsbILAjr3Hdm8WmThZifS pwWXbiEsppHS7jF4c6gN7lZSaZW0Zv295OmfvQNGw4GekiUsulCM/hMutZBIGr8HErlB okb1qPZMmXudgM3oqTSQ0SMoskteJDIWuoy2XXUFlMDKEfp0mRHKY9Jxf8RDrjD4+y+k R5L8OgdgvHhpVK2XEalHIq/NL0QwsvOYAuQzE01xtr7GBI0r7oq5x49Dd3yWWrScKvxf 7ucpd6qXI/udJR2/g0IuZEl27HQOaLbrRuhuiDNy6z35pHDvpWcPou6S7xAj4HUNUP6j 0dog== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:cc:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:user-agent :mime-version:message-id:references:auto-submitted:to:date:from :dkim-signature:dkim-signature:dkim-signature; bh=cYX01AujP0kkwuXz4g3k83HMFhr7lsmIXX5faZOpBOw=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=cNokSYTRwrRuSi+OecPOC0V//6HjtzIEVIVIjJ84t1uU6VR/ImAwDKLkYLPCjxPLOD U52mdmn6dl+LjXEitykN/68tlC6fSg4alLYZ9umzFU5T2FkJURRu/74masS37pLPKXKc LORk3HGTyFTLNpcXQKEtADn79RztFhAE7aQUjE2/iiidks3kp0NmzFzroIkzlYUxnjDB RlJk3OWskSUlbPbiBzt9hmUo0I27KhW9InxW6MDSGpLfKywcylMK1TkibOFgOVstrwMd 5J0E7LAah+2vFT9HEHLNpXE4We0RYbI3h6IxS2oX8fgV2BmbhRXQ65k538jDLNzPlmMG a8mw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="kQq7q/V/"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=hWbjE0ft; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b="Q/g/nT8x"; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net; dara=fail header.i=@openvpn.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 98e67ed59e1d1-2cdb76074e6si14826961a91.137.2024.07.30.02.25.31 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 30 Jul 2024 02:25:31 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="kQq7q/V/"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=hWbjE0ft; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b="Q/g/nT8x"; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net; dara=fail header.i=@openvpn.net 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.95) (envelope-from ) id 1sYj6N-0002pq-4S; Tue, 30 Jul 2024 09:25:03 +0000 Received: from [172.30.29.66] (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.95) (envelope-from ) id 1sYj6E-0002p3-Tv for openvpn-devel@lists.sourceforge.net; Tue, 30 Jul 2024 09:24:54 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Content-Transfer-Encoding:MIME-Version :Message-ID:Reply-To:References:Subject:List-Unsubscribe:List-Id:Cc:To:Date: From:Sender:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help: List-Subscribe:List-Post:List-Owner:List-Archive; bh=/UsiMDcLWGdcnS3mXtpEZEOzos3Xl5xy1j6IiWJkt8Q=; b=kQq7q/V/mgNkqlz0/XKAn+E5Ed rXIPpfWUzh4RDJDvRuCJfi8tEUssdBCIpER1eaeB3IKb5k3yKZujhaxCcdT3tciBrP57UAYiZYRzh HfjcrlWkJBXzL2BQYftojRSJgQrUZVgvgi4210ZFVoMV2oI+MPO1txpM7wrA5PpF7ALw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Content-Transfer-Encoding:MIME-Version:Message-ID:Reply-To: References:Subject:List-Unsubscribe:List-Id:Cc:To:Date:From:Sender:Content-ID :Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To: Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help:List-Subscribe:List-Post: List-Owner:List-Archive; bh=/UsiMDcLWGdcnS3mXtpEZEOzos3Xl5xy1j6IiWJkt8Q=; b=h WbjE0ftFHqDlmfyw6Myj22DdSOPOfdreaVAhiPjmAT23jAW3bI4YfPxWutLDxY55iZK+jYKEjxSvs Gh3kk5YihFSp9nz2wp+5mecm3+dNrtBxa+a0d3JdfR6b2JGnHKTCM4+lI7HxxjR1R1xmycLiY3dMP gtxASoH2xrJjViI8=; Received: from mail-lj1-f175.google.com ([209.85.208.175]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1sYj69-000793-Un for openvpn-devel@lists.sourceforge.net; Tue, 30 Jul 2024 09:24:54 +0000 Received: by mail-lj1-f175.google.com with SMTP id 38308e7fff4ca-2ef2d582e31so53568601fa.2 for ; Tue, 30 Jul 2024 02:24:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1722331483; x=1722936283; darn=lists.sourceforge.net; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from:from:to:cc :subject:date:message-id:reply-to; bh=/UsiMDcLWGdcnS3mXtpEZEOzos3Xl5xy1j6IiWJkt8Q=; b=Q/g/nT8xq+Y9IoRceb/fswVa+/4YaQh1Uq44mG9ztBlBQvGEsERBWIL6WNTS70Kpwu TJn7IjbYEKnh9xo6qOGIoxwoDUkrvhg4NXxENZtapHWUH3ab1Ux/X3qLjD4h8BKh+wwh dy0pZOmtChud4J8q+E7w7ntfvwxrLdhhYIMP16XLy6FgSnpwD6e19KOFVMqON1GsfvdT +8ntCUspz+Oo72XpLmxHZC1KbQNdQQhdUqB5UOsRVEBSoLW9H2B/5thW4p/ARRCdvtgG VqarN7XjdkVBCD9uqJH/oH0BnYmtq6LFPht9ylEEGNyjIPV+/uquvvOajvd9I8248uHC C+hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722331483; x=1722936283; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/UsiMDcLWGdcnS3mXtpEZEOzos3Xl5xy1j6IiWJkt8Q=; b=TMwKIkZQjVEx+8OqEIjOZ6e3DU+gj7F95JdXqGnipzQSF3qO7gpecG4gbMDSUuLP0H 1DzrqYbAoWXxdHbq18mnp42/RpMZVJaUU2w4cGelI3PpUCaQkJVJAWMqYGv66/2QmKRz lzkjk6TKWft4cfzf8IYBpiMEF/ZJlMPDxj487HvmoEDwz8LcayfhfHnBEli0ontRAiW5 3RDYBWsa2G4uCZyDXktZQebY7z2qo0XR4K3Xy7us6DFmb0MJ63eFIZjN45BhmphlHZwx 8/nu2oSIItxjCCVBK0AaMIn7mICc5ue8/D8WpfoZ9A/pRs9oAxReyxOIWWa+fHet894a HsJQ== X-Gm-Message-State: AOJu0YwpuJyATzBZPOnVH9oFXAG7+TwL1sD7HGPVonfQ2q7QUUJGpyFN QYUqUpPsGD/fT50F2SUZcj43gu/yWXsvg4XcZgAMdKldfd7qiKhH4Lw0PlukniA= X-Received: by 2002:a2e:9058:0:b0:2ef:2b45:b71d with SMTP id 38308e7fff4ca-2f12ee23c6amr61918191fa.24.1722331482164; Tue, 30 Jul 2024 02:24:42 -0700 (PDT) Received: from gerrit.openvpn.in (ec2-18-159-0-78.eu-central-1.compute.amazonaws.com. [18.159.0.78]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42805730e5dsm208918115e9.2.2024.07.30.02.24.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 30 Jul 2024 02:24:41 -0700 (PDT) From: "mrbff (Code Review)" X-Google-Original-From: "mrbff (Code Review)" X-Gerrit-PatchSet: 1 Date: Tue, 30 Jul 2024 09:24:41 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: I87777e74b1fd34781e1d72c9f994eb84f39d800c X-Gerrit-Change-Number: 721 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: cafa48bd51ffaf181364723e75db34bb6415eabc References: Message-ID: MIME-Version: 1.0 User-Agent: Gerrit/3.8.2 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-2.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: Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: openvpn.net] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.208.175 listed in list.dnswl.org] 0.0 RCVD_IN_VALIDITY_SAFE_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [209.85.208.175 listed in sa-trusted.bondedsender.org] 0.0 RCVD_IN_VALIDITY_RPBL_BLOCKED RBL: ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. [209.85.208.175 listed in bl.score.senderscore.com] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.208.175 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 WEIRD_PORT URI: Uses non-standard port number for HTTP 0.0 HTML_MESSAGE BODY: HTML included in message -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.0 T_KAM_HTML_FONT_INVALID Test for Invalidly Named or Formatted Colors in HTML X-Headers-End: 1sYj69-000793-Un Subject: [Openvpn-devel] [L] Change in openvpn[master]: route: extended logic to omit gateway when unnecessary 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: , Reply-To: marco@mandelbit.com, arne-openvpn@rfc2549.org, openvpn-devel@lists.sourceforge.net, frank@lichtenheld.com Cc: openvpn-devel Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1805995507763553251?= X-GMAIL-MSGID: =?utf-8?q?1805995507763553251?= X-getmail-filter-classifier: gerrit message type newchange Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit http://gerrit.openvpn.net/c/openvpn/+/721?usp=email to review the following change. Change subject: route: extended logic to omit gateway when unnecessary ...................................................................... route: extended logic to omit gateway when unnecessary Extracted and extended the logic behind 'gateway_needed' both in add_route() and add_route_ipv6(). Other than checking the dev-type, special routes and if the gateway is on-link, - set gateway_needed to true if the vpn instance is a multipoint server and DCO is enabled. - set gateway_needed to false if the gateway is in the vpn subnet. Additionally, extended support for these checks and conditions to DARWIN and BSD-based operating systems. These changes ensure that the gateway is only included when necessary, optimizing route configuration and potentially reducing redundant route entries. Change-Id: I87777e74b1fd34781e1d72c9f994eb84f39d800c Signed-off-by: Marco Baffo --- M src/openvpn/forward.c M src/openvpn/init.c M src/openvpn/init.h M src/openvpn/route.c M src/openvpn/route.h M src/openvpn/tun.c M src/openvpn/tun.h 7 files changed, 420 insertions(+), 256 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/21/721/1 diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 40b7cc4..8c22bc9 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -421,7 +421,7 @@ check_add_routes_action(struct context *c, const bool errors) { bool route_status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); + c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx, c->mode == CM_TOP); int flags = (errors ? ISC_ERRORS : 0); flags |= (!route_status ? ISC_ROUTE_ERRORS : 0); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index a49e563..b0b2145 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1134,7 +1134,7 @@ tuncfg(options->dev, options->dev_type, options->dev_node, options->persist_mode, options->username, options->groupname, &options->tuntap_options, - ctx); + ctx, options->mode == MODE_SERVER); if (options->persist_mode && options->lladdr) { set_lladdr(ctx, options->dev, options->lladdr, NULL); @@ -1689,13 +1689,14 @@ const struct tuntap *tt, const struct plugin_list *plugins, struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { bool ret = true; if (!options->route_noexec && ( route_list || route_ipv6_list ) ) { ret = add_routes(route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS(options), - es, ctx); + es, ctx, is_multipoint); setenv_int(es, "redirect_gateway", route_did_redirect_default_gateway(route_list)); } #ifdef ENABLE_MANAGEMENT @@ -1898,7 +1899,7 @@ c->options.dev_node, &gc); do_ifconfig(c->c1.tuntap, guess, c->c2.frame.tun_mtu, c->c2.es, - &c->net_ctx); + &c->net_ctx, c->mode == CM_TOP); } /* possibly add routes */ @@ -1906,7 +1907,7 @@ { /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */ bool status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); + c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx, c->mode == CM_TOP); *error_flags |= (status ? 0 : ISC_ROUTE_ERRORS); } #ifdef TARGET_ANDROID @@ -1934,7 +1935,7 @@ && ifconfig_order() == IFCONFIG_AFTER_TUN_OPEN) { do_ifconfig(c->c1.tuntap, c->c1.tuntap->actual_name, - c->c2.frame.tun_mtu, c->c2.es, &c->net_ctx); + c->c2.frame.tun_mtu, c->c2.es, &c->net_ctx, c->mode == CM_TOP); } /* run the up script */ @@ -1960,7 +1961,7 @@ if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) { int status = do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx); + c->c1.tuntap, c->plugins, c->c2.es, &c->net_ctx, c->mode == CM_TOP); *error_flags |= (status ? 0 : ISC_ROUTE_ERRORS); } @@ -2017,7 +2018,7 @@ { undo_ifconfig(c->c1.tuntap, &c->net_ctx); } - close_tun(c->c1.tuntap, &c->net_ctx); + close_tun(c->c1.tuntap, &c->net_ctx, c->mode == CM_TOP); c->c1.tuntap = NULL; } c->c1.tuntap_owned = false; @@ -2086,7 +2087,7 @@ delete_routes(c->c1.route_list, c->c1.route_ipv6_list, c->c1.tuntap, ROUTE_OPTION_FLAGS(&c->options), - c->c2.es, &c->net_ctx); + c->c2.es, &c->net_ctx, c->mode == CM_TOP); } /* actually close tun/tap device based on --down-pre flag */ diff --git a/src/openvpn/init.h b/src/openvpn/init.h index ea7eb30..82eec7e 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -74,7 +74,7 @@ bool do_route(const struct options *options, struct route_list *route_list, struct route_ipv6_list *route_ipv6_list, const struct tuntap *tt, const struct plugin_list *plugins, struct env_set *es, - openvpn_net_ctx_t *ctx); + openvpn_net_ctx_t *ctx, const bool is_multipoint); void close_instance(struct context *c); diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 06a4919..71b5b42 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -77,7 +77,7 @@ static void delete_route(struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx); + openvpn_net_ctx_t *ctx, const bool is_multipoint); static void get_bypass_addresses(struct route_bypass *rb, const unsigned int flags); @@ -927,7 +927,8 @@ unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { struct route_ipv4 r; CLEAR(r); @@ -935,7 +936,7 @@ r.network = network; r.netmask = netmask; r.gateway = gateway; - return add_route(&r, tt, flags, rgi, es, ctx); + return add_route(&r, tt, flags, rgi, es, ctx, is_multipoint); } static void @@ -946,7 +947,8 @@ unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { struct route_ipv4 r; CLEAR(r); @@ -954,7 +956,7 @@ r.network = network; r.netmask = netmask; r.gateway = gateway; - delete_route(&r, tt, flags, rgi, es, ctx); + delete_route(&r, tt, flags, rgi, es, ctx, is_multipoint); } static bool @@ -964,7 +966,8 @@ unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { int ret = true; for (int i = 0; i < rb->n_bypass; ++i) @@ -972,7 +975,7 @@ if (rb->bypass[i]) { ret = add_route3(rb->bypass[i], IPV4_NETMASK_HOST, gateway, tt, - flags | ROUTE_REF_GW, rgi, es, ctx) && ret; + flags | ROUTE_REF_GW, rgi, es, ctx, is_multipoint) && ret; } } return ret; @@ -985,7 +988,8 @@ unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { int i; for (i = 0; i < rb->n_bypass; ++i) @@ -999,7 +1003,8 @@ flags | ROUTE_REF_GW, rgi, es, - ctx); + ctx, + is_multipoint); } } } @@ -1007,7 +1012,7 @@ static bool redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, const bool is_multipoint) { const char err[] = "NOTE: unable to redirect IPv4 default gateway --"; bool ret = true; @@ -1059,7 +1064,7 @@ { ret = add_route3(rl->spec.remote_host, IPV4_NETMASK_HOST, rl->rgi.gateway.addr, tt, flags | ROUTE_REF_GW, - &rl->rgi, es, ctx); + &rl->rgi, es, ctx, is_multipoint); rl->iflags |= RL_DID_LOCAL; } else @@ -1071,7 +1076,7 @@ /* route DHCP/DNS server traffic through original default gateway */ ret = add_bypass_routes(&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, - &rl->rgi, es, ctx) && ret; + &rl->rgi, es, ctx, is_multipoint) && ret; if (rl->flags & RG_REROUTE_GW) { @@ -1079,11 +1084,11 @@ { /* add new default route (1st component) */ ret = add_route3(0x00000000, 0x80000000, rl->spec.remote_endpoint, - tt, flags, &rl->rgi, es, ctx) && ret; + tt, flags, &rl->rgi, es, ctx, is_multipoint) && ret; /* add new default route (2nd component) */ ret = add_route3(0x80000000, 0x80000000, rl->spec.remote_endpoint, - tt, flags, &rl->rgi, es, ctx) && ret; + tt, flags, &rl->rgi, es, ctx, is_multipoint) && ret; } else { @@ -1092,12 +1097,12 @@ { /* delete default route */ del_route3(0, 0, rl->rgi.gateway.addr, tt, - flags | ROUTE_REF_GW, &rl->rgi, es, ctx); + flags | ROUTE_REF_GW, &rl->rgi, es, ctx, is_multipoint); } /* add new default route */ ret = add_route3(0, 0, rl->spec.remote_endpoint, tt, - flags, &rl->rgi, es, ctx) && ret; + flags, &rl->rgi, es, ctx, is_multipoint) && ret; } } @@ -1112,7 +1117,8 @@ undo_redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { if (rl && rl->iflags & RL_DID_REDIRECT_DEFAULT_GATEWAY) { @@ -1126,13 +1132,14 @@ flags | ROUTE_REF_GW, &rl->rgi, es, - ctx); + ctx, + is_multipoint); rl->iflags &= ~RL_DID_LOCAL; } /* delete special DHCP/DNS bypass route */ del_bypass_routes(&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, - &rl->rgi, es, ctx); + &rl->rgi, es, ctx, is_multipoint); if (rl->flags & RG_REROUTE_GW) { @@ -1146,7 +1153,8 @@ flags, &rl->rgi, es, - ctx); + ctx, + is_multipoint); /* delete default route (2nd component) */ del_route3(0x80000000, @@ -1156,7 +1164,8 @@ flags, &rl->rgi, es, - ctx); + ctx, + is_multipoint); } else { @@ -1168,12 +1177,13 @@ flags, &rl->rgi, es, - ctx); + ctx, + is_multipoint); /* restore original default route if there was any */ if (rl->rgi.flags & RGI_ADDR_DEFINED) { add_route3(0, 0, rl->rgi.gateway.addr, tt, - flags | ROUTE_REF_GW, &rl->rgi, es, ctx); + flags | ROUTE_REF_GW, &rl->rgi, es, ctx, is_multipoint); } } } @@ -1185,9 +1195,10 @@ bool add_routes(struct route_list *rl, struct route_ipv6_list *rl6, const struct tuntap *tt, unsigned int flags, - const struct env_set *es, openvpn_net_ctx_t *ctx) + const struct env_set *es, openvpn_net_ctx_t *ctx, + const bool is_multipoint) { - bool ret = redirect_default_route_to_vpn(rl, tt, flags, es, ctx); + bool ret = redirect_default_route_to_vpn(rl, tt, flags, es, ctx, is_multipoint); if (rl && !(rl->iflags & RL_ROUTES_ADDED) ) { struct route_ipv4 *r; @@ -1218,9 +1229,9 @@ check_subnet_conflict(r->network, r->netmask, "route"); if (flags & ROUTE_DELETE_FIRST) { - delete_route(r, tt, flags, &rl->rgi, es, ctx); + delete_route(r, tt, flags, &rl->rgi, es, ctx, is_multipoint); } - ret = add_route(r, tt, flags, &rl->rgi, es, ctx) && ret; + ret = add_route(r, tt, flags, &rl->rgi, es, ctx, is_multipoint) && ret; } rl->iflags |= RL_ROUTES_ADDED; } @@ -1240,9 +1251,9 @@ { if (flags & ROUTE_DELETE_FIRST) { - delete_route_ipv6(r, tt, flags, es, ctx); + delete_route_ipv6(r, tt, flags, es, ctx, is_multipoint); } - ret = add_route_ipv6(r, tt, flags, es, ctx) && ret; + ret = add_route_ipv6(r, tt, flags, es, ctx, is_multipoint) && ret; } rl6->iflags |= RL_ROUTES_ADDED; } @@ -1253,19 +1264,20 @@ void delete_routes(struct route_list *rl, struct route_ipv6_list *rl6, const struct tuntap *tt, unsigned int flags, - const struct env_set *es, openvpn_net_ctx_t *ctx) + const struct env_set *es, openvpn_net_ctx_t *ctx, + const bool is_multipoint) { if (rl && rl->iflags & RL_ROUTES_ADDED) { struct route_ipv4 *r; for (r = rl->routes; r; r = r->next) { - delete_route(r, tt, flags, &rl->rgi, es, ctx); + delete_route(r, tt, flags, &rl->rgi, es, ctx, is_multipoint); } rl->iflags &= ~RL_ROUTES_ADDED; } - undo_redirect_default_route_to_vpn(rl, tt, flags, es, ctx); + undo_redirect_default_route_to_vpn(rl, tt, flags, es, ctx, is_multipoint); if (rl) { @@ -1277,7 +1289,7 @@ struct route_ipv6 *r6; for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) { - delete_route_ipv6(r6, tt, flags, es, ctx); + delete_route_ipv6(r6, tt, flags, es, ctx, is_multipoint); } rl6->iflags &= ~RL_ROUTES_ADDED; } @@ -1561,13 +1573,47 @@ } #endif +static bool +is_gateway_needed_ipv4(const struct route_ipv4 *r4, + const struct route_gateway_info *rgi, + const struct tuntap *tt, + const bool is_multipoint) +{ + +#ifndef _WIN32 + + if (rgi && (rgi->flags & RGI_IFACE_DEFINED) && rgi->iface[0] != 0) /* vpn server special route */ + { + if (rgi->flags & RGI_ADDR_DEFINED && r4->gateway != 0) + { + return true; + } + } + +#endif + + if (tt->type == DEV_TYPE_TAP + && !( (r4->flags & RT_METRIC_DEFINED) && r4->metric == 0 ) ) + { + return true; + } + + if (is_multipoint && !tt->options.disable_dco) + { + return true; + } + + return false; +} + bool add_route(struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, /* may be NULL */ const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { int status = 0; int is_local_route; @@ -1595,23 +1641,7 @@ goto done; } - #ifndef _WIN32 - - if (rgi && (rgi->flags & RGI_IFACE_DEFINED) && rgi->iface[0] != 0) /* vpn server special route */ - { - if (rgi->flags & RGI_ADDR_DEFINED && r->gateway != 0) - { - gateway_needed = true; - } - } - - #endif - - if (tt->type == DEV_TYPE_TAP - && !( (r->flags & RT_METRIC_DEFINED) && r->metric == 0 ) ) - { - gateway_needed = true; - } + gateway_needed = is_gateway_needed_ipv4(r, rgi, tt, is_multipoint); if (gateway_needed && r->gateway == 0) { @@ -1623,11 +1653,12 @@ goto done; } -#if defined(TARGET_LINUX) - const char *iface = tt->actual_name; +#if !defined(_WIN32) && !defined(TARGET_SOLARIS) \ + && !defined(TARGET_AIX) + const char *device = tt->actual_name; if (!gateway_needed && rgi && (rgi->flags & RGI_IFACE_DEFINED) && rgi->iface[0] != 0) /* vpn server special route */ { - iface = rgi->iface; + device = rgi->iface; } #endif @@ -1636,7 +1667,7 @@ if (is_on_link(is_local_route, flags, rgi)) { - iface = rgi->iface; + device = rgi->iface; } if (r->flags & RT_METRIC_DEFINED) @@ -1647,7 +1678,7 @@ status = RTA_SUCCESS; int ret = net_route_v4_add(ctx, &r->network, netmask_to_netbits2(r->netmask), gateway_needed ? &r->gateway : NULL, - iface, 0, metric); + device, 0, metric); if (ret == -EEXIST) { msg(D_ROUTE, "NOTE: Linux route add command failed because route exists"); @@ -1664,7 +1695,7 @@ if (rgi) { - snprintf(out, sizeof(out), "%s %s %s dev %s", network, netmask, gateway, rgi->iface); + snprintf(out, sizeof(out), "%s %s %s dev %s", network, netmask, gateway, device); } else { @@ -1768,9 +1799,9 @@ "ERROR: Solaris route add command failed"); status = ret ? RTA_SUCCESS : RTA_ERROR; -#elif defined(TARGET_FREEBSD) +#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) - argv_printf(&argv, "%s add", + argv_printf(&argv, "%s add ", ROUTE_PATH); #if 0 @@ -1780,45 +1811,28 @@ } #endif - argv_printf_cat(&argv, "-net %s %s %s", - network, - gateway, - netmask); - - /* FIXME -- add on-link support for FreeBSD */ - - argv_msg(D_ROUTE, &argv); - bool ret = openvpn_execve_check(&argv, es, 0, - "ERROR: FreeBSD route add command failed"); - status = ret ? RTA_SUCCESS : RTA_ERROR; - -#elif defined(TARGET_DRAGONFLY) - - argv_printf(&argv, "%s add", - ROUTE_PATH); - -#if 0 - if (r->flags & RT_METRIC_DEFINED) + if (gateway_needed) { - argv_printf_cat(&argv, "-rtt %d", r->metric); + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); } -#endif - - argv_printf_cat(&argv, "-net %s %s %s", - network, - gateway, - netmask); - - /* FIXME -- add on-link support for Dragonfly */ + else + { + argv_printf_cat(&argv, "-net %s -iface %s", + network, + device); + } argv_msg(D_ROUTE, &argv); bool ret = openvpn_execve_check(&argv, es, 0, - "ERROR: DragonFly route add command failed"); + "ERROR: BSD route add command failed"); status = ret ? RTA_SUCCESS : RTA_ERROR; #elif defined(TARGET_DARWIN) - argv_printf(&argv, "%s add", + argv_printf(&argv, "%s add ", ROUTE_PATH); #if 0 @@ -1839,10 +1853,19 @@ } else { - argv_printf_cat(&argv, "-net %s %s %s", - network, - gateway, - netmask); + if (gateway_needed) + { + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); + } + else + { + argv_printf_cat(&argv, "-net %s -interface %s", + network, + device); + } } argv_msg(D_ROUTE, &argv); @@ -1852,7 +1875,7 @@ #elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - argv_printf(&argv, "%s add", + argv_printf(&argv, "%s add ", ROUTE_PATH); #if 0 @@ -1862,12 +1885,20 @@ } #endif - argv_printf_cat(&argv, "-net %s %s -netmask %s", - network, - gateway, - netmask); - - /* FIXME -- add on-link support for OpenBSD/NetBSD */ + if (gateway_needed) + { + argv_printf_cat(&argv, "-net %s %s -netmask %s", + network, + gateway, + netmask); + } + else + { + argv_printf_cat(&argv, "-net %s -netmask %s -link -iface %s", + network, + netmask, + device); + } argv_msg(D_ROUTE, &argv); bool ret = openvpn_execve_check(&argv, es, 0, @@ -1932,10 +1963,98 @@ } } +static inline struct in6_addr +netbits_to_netmask_ipv6(const int netbits) +{ + struct in6_addr netmask = {{{0}}}; + + if (netbits > 0 && netbits <= 128) + { + const int full_bytes = netbits / 8; + int i; + for (i = 0; i < full_bytes; i++) + { + netmask.s6_addr[i] = 0xFF; + } + if (netbits % 8) + { + netmask.s6_addr[i] = (0xFF << (8 - (netbits % 8))); + } + } + + return netmask; +} + +static bool +is_gateway_in_vpn_subnet_ipv6(const struct in6_addr *gateway, + const struct in6_addr *vpn_subnet, + int netbits) +{ + struct in6_addr netmask = netbits_to_netmask_ipv6(netbits); + + for (int i = 0; i < 16; i++) + { + if ((gateway->s6_addr[i] & netmask.s6_addr[i]) != (vpn_subnet->s6_addr[i] & netmask.s6_addr[i])) + { + return false; + } + } + return true; +} + +static bool +is_gateway_needed_ipv6(const struct route_ipv6 *r6, + const struct tuntap *tt, + const char *network, + const bool is_multipoint) +{ + +#ifndef _WIN32 + if (r6->iface != NULL) /* VPN server special route */ + { + if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway)) + { + return true; + } + } +#endif + + /* + * Filter out routes which are essentially no-ops + * (not currently done for IPv6) + */ + + /* On "tun" interface, we never set a gateway if the operating system + * can do "route to interface" - it does not add value, as the target + * dev already fully qualifies the route destination on point-to-point + * interfaces. OTOH, on "tap" interface, we must always set the + * gateway unless the route is to be an on-link network + */ + if (tt->type == DEV_TYPE_TAP + && !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) + { + return true; + } + + /* if is server and dco enabled, the gateway is needed*/ + if (is_multipoint && !tt->options.disable_dco) + { + return true; + } + + if (is_gateway_in_vpn_subnet_ipv6(&r6->gateway, &tt->local_ipv6, tt->netbits_ipv6)) + { + msg(D_ROUTE, "Ignoring gateway in VPN subnet for route %s/%d", network, r6->netbits); + return false; + } + + return false; +} + bool add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, const bool is_multipoint) { int status = 0; bool gateway_needed = false; @@ -1948,22 +2067,12 @@ struct argv argv = argv_new(); struct gc_arena gc = gc_new(); -#ifndef _WIN32 - const char *device = tt->actual_name; - if (r6->iface != NULL) /* vpn server special route */ - { - device = r6->iface; - if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) - { - gateway_needed = true; - } - } -#endif - route_ipv6_clear_host_bits(r6); const char *network = print_in6_addr( r6->network, 0, &gc); const char *gateway = print_in6_addr( r6->gateway, 0, &gc); + gateway_needed = is_gateway_needed_ipv6(r6, tt, network, is_multipoint); + #if defined(TARGET_DARWIN) \ || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) @@ -1982,6 +2091,15 @@ } #endif +#if !defined(_WIN32) + + const char *device = tt->actual_name; + if (r6->iface != NULL) + { + device = r6->iface; + } +#endif + #ifndef _WIN32 msg(D_ROUTE, "add_route_ipv6(%s/%d -> %s metric %d) dev %s", network, r6->netbits, gateway, r6->metric, device ); @@ -1991,23 +2109,6 @@ r6->adapter_index ? r6->adapter_index : tt->adapter_index); #endif - /* - * Filter out routes which are essentially no-ops - * (not currently done for IPv6) - */ - - /* On "tun" interface, we never set a gateway if the operating system - * can do "route to interface" - it does not add value, as the target - * dev already fully qualifies the route destination on point-to-point - * interfaces. OTOH, on "tap" interface, we must always set the - * gateway unless the route is to be an on-link network - */ - if (tt->type == DEV_TYPE_TAP - && !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) - { - gateway_needed = true; - } - if (gateway_needed && IN6_IS_ADDR_UNSPECIFIED(&r6->gateway)) { msg(M_WARN, "ROUTE6 WARNING: " PACKAGE_NAME " needs a gateway " @@ -2020,6 +2121,7 @@ #if defined(TARGET_LINUX) int metric = -1; + if ((r6->flags & RT_METRIC_DEFINED) && (r6->metric > 0)) { metric = r6->metric; @@ -2089,7 +2191,7 @@ #elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) - argv_printf(&argv, "%s add -inet6 %s/%d", + argv_printf(&argv, "%s add -inet6 %s/%d ", ROUTE_PATH, network, r6->netbits); @@ -2110,7 +2212,7 @@ #elif defined(TARGET_DARWIN) - argv_printf(&argv, "%s add -inet6 %s -prefixlen %d", + argv_printf(&argv, "%s add -inet6 %s -prefixlen %d ", ROUTE_PATH, network, r6->netbits ); @@ -2128,26 +2230,27 @@ "ERROR: MacOS X route add -inet6 command failed"); status = ret ? RTA_SUCCESS : RTA_ERROR; -#elif defined(TARGET_OPENBSD) +#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - argv_printf(&argv, "%s add -inet6 %s -prefixlen %d %s", + argv_printf(&argv, "%s add -inet6 %s -prefixlen %d ", ROUTE_PATH, - network, r6->netbits, gateway ); + network, r6->netbits); + + if (gateway_needed) + { + argv_printf_cat(&argv, "%s", gateway); + } + else + { + argv_printf_cat(&argv, "-link -iface %s", device); + } + /* FIX ME: in NetBSD in TUN mode, the route is already added by ifconfig + * so add_route_ipv6 fail with 'Invalid argument' or 'File exists' + */ argv_msg(D_ROUTE, &argv); bool ret = openvpn_execve_check(&argv, es, 0, - "ERROR: OpenBSD route add -inet6 command failed"); - status = ret ? RTA_SUCCESS : RTA_ERROR; - -#elif defined(TARGET_NETBSD) - - argv_printf(&argv, "%s add -inet6 %s/%d %s", - ROUTE_PATH, - network, r6->netbits, gateway ); - - argv_msg(D_ROUTE, &argv); - bool ret = openvpn_execve_check(&argv, es, 0, - "ERROR: NetBSD route add -inet6 command failed"); + "ERROR: OpenBSD/NetBSD route add -inet6 command failed"); status = ret ? RTA_SUCCESS : RTA_ERROR; #elif defined(TARGET_AIX) @@ -2187,7 +2290,8 @@ unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, + const bool is_multipoint) { #if !defined(TARGET_LINUX) const char *network; @@ -2202,6 +2306,21 @@ #endif int is_local_route; +#if defined(TARGET_DARWIN) || defined(TARGET_LINUX) \ + || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ + || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) + + bool gateway_needed = is_gateway_needed_ipv4(r, rgi, tt, is_multipoint); + +#if !defined(TARGET_OPENBSD) && !defined(TARGET_NETBSD) + const char *device = tt->actual_name; + if (!gateway_needed && rgi && (rgi->flags & RGI_IFACE_DEFINED) && rgi->iface[0] != 0) /* vpn server special route */ + { + device = rgi->iface; + } +#endif +#endif + if ((r->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) { return; @@ -2228,13 +2347,20 @@ #if defined(TARGET_LINUX) metric = -1; + + if (is_on_link(is_local_route, flags, rgi)) + { + device = rgi->iface; + } + if (r->flags & RT_METRIC_DEFINED) { metric = r->metric; } if (net_route_v4_del(ctx, &r->network, netmask_to_netbits2(r->netmask), - &r->gateway, NULL, 0, metric) < 0) + gateway_needed ? &r->gateway : NULL, + device, 0, metric) < 0) { msg(M_WARN, "ERROR: Linux route delete command failed"); } @@ -2293,27 +2419,26 @@ argv_msg(D_ROUTE, &argv); openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete command failed"); -#elif defined(TARGET_FREEBSD) +#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) - argv_printf(&argv, "%s delete -net %s %s %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete", ROUTE_PATH); + + if (gateway_needed) + { + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); + } + else + { + argv_printf_cat(&argv, "-net %s -iface %s", + network, + device); + } argv_msg(D_ROUTE, &argv); - openvpn_execve_check(&argv, es, 0, "ERROR: FreeBSD route delete command failed"); - -#elif defined(TARGET_DRAGONFLY) - - argv_printf(&argv, "%s delete -net %s %s %s", - ROUTE_PATH, - network, - gateway, - netmask); - - argv_msg(D_ROUTE, &argv); - openvpn_execve_check(&argv, es, 0, "ERROR: DragonFly route delete command failed"); + openvpn_execve_check(&argv, es, 0, "ERROR: BSD route delete command failed"); #elif defined(TARGET_DARWIN) @@ -2327,11 +2452,22 @@ } else { - argv_printf(&argv, "%s delete -net %s %s %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete ", + ROUTE_PATH); + + if (gateway_needed) + { + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); + } + else + { + argv_printf_cat(&argv, "-net %s -interface %s", + network, + device); + } } argv_msg(D_ROUTE, &argv); @@ -2339,11 +2475,22 @@ #elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - argv_printf(&argv, "%s delete -net %s %s -netmask %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete ", + ROUTE_PATH); + + if (gateway_needed) + { + argv_printf_cat(&argv, "-net %s %s -netmask %s", + network, + gateway, + netmask); + } + else + { + argv_printf_cat(&argv, "-net %s -netmask %s", + network, + netmask); + } argv_msg(D_ROUTE, &argv); openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed"); @@ -2378,7 +2525,7 @@ void delete_route_ipv6(const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es, - openvpn_net_ctx_t *ctx) + openvpn_net_ctx_t *ctx, const bool is_multipoint) { const char *network; @@ -2391,23 +2538,15 @@ #if !defined(TARGET_LINUX) const char *gateway; #endif -#if !defined(TARGET_SOLARIS) - bool gateway_needed = false; +#if defined(TARGET_DARWIN) || defined(TARGET_LINUX) \ + || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) + const char *device = tt->actual_name; if (r6->iface != NULL) /* vpn server special route */ { device = r6->iface; - gateway_needed = true; } - /* if we used a gateway on "add route", we also need to specify it on - * delete, otherwise some OSes will refuse to delete the route - */ - if (tt->type == DEV_TYPE_TAP - && !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) - { - gateway_needed = true; - } #endif #endif @@ -2419,6 +2558,16 @@ gateway = print_in6_addr( r6->gateway, 0, &gc); #endif +#if defined(TARGET_DARWIN) || defined(TARGET_LINUX) \ + || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ + || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) + /* if we used a gateway on "add route", we also need to specify it on + * delete, otherwise some OSes will refuse to delete the route + */ + bool gateway_needed = false; + gateway_needed = is_gateway_needed_ipv6(r6, tt, network, is_multipoint); +#endif + #if defined(TARGET_DARWIN) \ || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) @@ -2513,23 +2662,19 @@ argv_msg(D_ROUTE, &argv); openvpn_execve_check(&argv, es, 0, "ERROR: MacOS X route delete -inet6 command failed"); -#elif defined(TARGET_OPENBSD) +#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - argv_printf(&argv, "%s delete -inet6 %s -prefixlen %d %s", + argv_printf(&argv, "%s delete -inet6 %s -prefixlen %d", ROUTE_PATH, - network, r6->netbits, gateway ); + network, r6->netbits); + + if (gateway_needed) + { + argv_printf_cat(&argv, "%s", gateway); + } argv_msg(D_ROUTE, &argv); - openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD route delete -inet6 command failed"); - -#elif defined(TARGET_NETBSD) - - argv_printf(&argv, "%s delete -inet6 %s/%d %s", - ROUTE_PATH, - network, r6->netbits, gateway ); - - argv_msg(D_ROUTE, &argv); - openvpn_execve_check(&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed"); + openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete -inet6 command failed"); #elif defined(TARGET_AIX) diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 421e7d2..4c3f317 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -271,13 +271,13 @@ void route_ipv6_clear_host_bits( struct route_ipv6 *r6 ); -bool add_route_ipv6(struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es, openvpn_net_ctx_t *ctx); +bool add_route_ipv6(struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es, openvpn_net_ctx_t *ctx, const bool is_multipoint); -void delete_route_ipv6(const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es, openvpn_net_ctx_t *ctx); +void delete_route_ipv6(const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es, openvpn_net_ctx_t *ctx, const bool is_multipoint); bool add_route(struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es, - openvpn_net_ctx_t *ctx); + openvpn_net_ctx_t *ctx, const bool is_multipoint); void add_route_to_option_list(struct route_option_list *l, const char *network, @@ -312,14 +312,16 @@ bool add_routes(struct route_list *rl, struct route_ipv6_list *rl6, const struct tuntap *tt, unsigned int flags, - const struct env_set *es, openvpn_net_ctx_t *ctx); + const struct env_set *es, openvpn_net_ctx_t *ctx, + const bool is_multipoint); void delete_routes(struct route_list *rl, struct route_ipv6_list *rl6, const struct tuntap *tt, unsigned int flags, const struct env_set *es, - openvpn_net_ctx_t *ctx); + openvpn_net_ctx_t *ctx, + const bool is_multipoint); void setenv_routes(struct env_set *es, const struct route_list *rl); diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index ce3d882..d878161 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1020,7 +1020,7 @@ */ static void add_route_connected_v6_net(struct tuntap *tt, - const struct env_set *es) + const struct env_set *es, const bool is_multipoint) { struct route_ipv6 r6; @@ -1030,11 +1030,11 @@ r6.gateway = tt->local_ipv6; r6.metric = 0; /* connected route */ r6.flags = RT_DEFINED | RT_METRIC_DEFINED; - add_route_ipv6(&r6, tt, 0, es, NULL); + add_route_ipv6(&r6, tt, 0, es, NULL, is_multipoint); } void -delete_route_connected_v6_net(const struct tuntap *tt) +delete_route_connected_v6_net(const struct tuntap *tt, const bool is_multipoint) { struct route_ipv6 r6; @@ -1045,7 +1045,7 @@ r6.metric = 0; /* connected route */ r6.flags = RT_DEFINED | RT_ADDED | RT_METRIC_DEFINED; route_ipv6_clear_host_bits(&r6); - delete_route_ipv6(&r6, tt, 0, NULL, NULL); + delete_route_ipv6(&r6, tt, 0, NULL, NULL, is_multipoint); } #endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */ @@ -1087,7 +1087,8 @@ */ static void do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu, - const struct env_set *es, openvpn_net_ctx_t *ctx) + const struct env_set *es, openvpn_net_ctx_t *ctx, + const bool is_multipoint) { #if !defined(TARGET_LINUX) struct argv argv = argv_new(); @@ -1205,7 +1206,7 @@ #if defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) \ || defined(TARGET_DARWIN) /* and, hooray, we explicitly need to add a route... */ - add_route_connected_v6_net(tt, es); + add_route_connected_v6_net(tt, es, is_multipoint); #endif #elif defined(TARGET_AIX) argv_printf(&argv, "%s %s inet6 %s/%d mtu %d up", IFCONFIG_PATH, ifname, @@ -1231,7 +1232,7 @@ do_address_service(true, AF_INET6, tt); if (tt->type == DEV_TYPE_TUN) { - add_route_connected_v6_net(tt, es); + add_route_connected_v6_net(tt, es, is_multipoint); } do_dns_service(true, AF_INET6, tt); do_set_mtu_service(tt, AF_INET6, tun_mtu); @@ -1259,7 +1260,7 @@ netsh_command(&argv, 4, M_FATAL); if (tt->type == DEV_TYPE_TUN) { - add_route_connected_v6_net(tt, es); + add_route_connected_v6_net(tt, es, is_multipoint); } /* set ipv6 dns servers if any are specified */ netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, tt->adapter_index); @@ -1291,7 +1292,7 @@ */ static void do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, - const struct env_set *es, openvpn_net_ctx_t *ctx) + const struct env_set *es, openvpn_net_ctx_t *ctx, const bool is_multipoint) { #if !defined(_WIN32) && !defined(TARGET_ANDROID) /* @@ -1415,7 +1416,7 @@ r.netmask = tt->remote_netmask; r.gateway = tt->local; r.metric = 0; - add_route(&r, tt, 0, NULL, es, NULL); + add_route(&r, tt, 0, NULL, es, NULL, is_multipoint); } #elif defined(TARGET_OPENBSD) @@ -1462,7 +1463,7 @@ r.network = tt->local & tt->remote_netmask; r.netmask = tt->remote_netmask; r.gateway = remote_end; - add_route(&r, tt, 0, NULL, es, NULL); + add_route(&r, tt, 0, NULL, es, NULL, is_multipoint); } #elif defined(TARGET_NETBSD) @@ -1504,7 +1505,7 @@ r.network = tt->local & tt->remote_netmask; r.netmask = tt->remote_netmask; r.gateway = remote_end; - add_route(&r, tt, 0, NULL, es, NULL); + add_route(&r, tt, 0, NULL, es, NULL, is_multipoint); } #elif defined(TARGET_DARWIN) @@ -1554,7 +1555,7 @@ r.network = tt->local & tt->remote_netmask; r.netmask = tt->remote_netmask; r.gateway = tt->local; - add_route(&r, tt, 0, NULL, es, NULL); + add_route(&r, tt, 0, NULL, es, NULL, is_multipoint); } #elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) @@ -1648,7 +1649,7 @@ /* execute the ifconfig command through the shell */ void do_ifconfig(struct tuntap *tt, const char *ifname, int tun_mtu, - const struct env_set *es, openvpn_net_ctx_t *ctx) + const struct env_set *es, openvpn_net_ctx_t *ctx, const bool is_multipoint) { msg(D_LOW, "do_ifconfig, ipv4=%d, ipv6=%d", tt->did_ifconfig_setup, tt->did_ifconfig_ipv6_setup); @@ -1668,12 +1669,12 @@ if (tt->did_ifconfig_setup) { - do_ifconfig_ipv4(tt, ifname, tun_mtu, es, ctx); + do_ifconfig_ipv4(tt, ifname, tun_mtu, es, ctx, is_multipoint); } if (tt->did_ifconfig_ipv6_setup) { - do_ifconfig_ipv6(tt, ifname, tun_mtu, es, ctx); + do_ifconfig_ipv6(tt, ifname, tun_mtu, es, ctx, is_multipoint); } /* release resources potentially allocated during interface setup */ @@ -2138,12 +2139,13 @@ } void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); close_tun_generic(tt); free(tt); + (void)is_multipoint; } int @@ -2307,7 +2309,8 @@ void tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, - const struct tuntap_options *options, openvpn_net_ctx_t *ctx) + const struct tuntap_options *options, openvpn_net_ctx_t *ctx, + const bool is_multipoint) { struct tuntap *tt; @@ -2347,14 +2350,14 @@ msg(M_ERR, "Cannot ioctl TUNSETGROUP(%s) %s", groupname, dev); } } - close_tun(tt, ctx); + close_tun(tt, ctx, is_multipoint); msg(M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF")); } #endif /* ENABLE_FEATURE_TUN_PERSIST */ void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); @@ -2366,6 +2369,7 @@ #endif close_tun_generic(tt); free(tt); + (void)is_multipoint; } int @@ -2677,7 +2681,7 @@ * Close TUN device. */ void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); @@ -2687,6 +2691,7 @@ clear_tuntap(tt); free(tt); + (void)is_multipoint; } static void @@ -2710,7 +2715,7 @@ argv_msg(M_INFO, &argv); openvpn_execve_check(&argv, es, 0, "Solaris ifconfig unplumb failed"); - close_tun(tt, NULL); + close_tun(tt, NULL, false); msg(M_FATAL, "Solaris ifconfig failed"); argv_free(&argv); } @@ -2774,10 +2779,12 @@ */ void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); + (void)is_multipoint; + /* only *TAP* devices need destroying, tun devices auto-self-destruct */ if (tt->type == DEV_TYPE_TUN || tt->persistent_if) @@ -2888,10 +2895,12 @@ * need to be explicitly destroyed */ void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); + (void)is_multipoint; + /* only tun devices need destroying, tap devices auto-self-destruct */ if (tt->type != DEV_TYPE_TUN || tt->persistent_if) @@ -3044,10 +3053,12 @@ * we need to call "ifconfig ... destroy" for cleanup */ void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); + (void)is_multipoint; + if (tt->persistent_if) /* keep pre-existing if around */ { close_tun_generic(tt); @@ -3161,12 +3172,13 @@ } void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); close_tun_generic(tt); free(tt); + (void)is_multipoint; } int @@ -3428,7 +3440,7 @@ } void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); @@ -3450,6 +3462,7 @@ free(tt); argv_free(&argv); gc_free(&gc); + (void)is_multipoint; } int @@ -3577,7 +3590,7 @@ /* tap devices need to be manually destroyed on AIX */ void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); @@ -3605,6 +3618,7 @@ free(tt); env_set_destroy(es); argv_free(&argv); + (void)is_multipoint; } int @@ -6892,7 +6906,7 @@ } static void -netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc) +netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc, const bool is_multipoint) { const char *ifconfig_ip_local; struct argv argv = argv_new(); @@ -6922,7 +6936,7 @@ if (ipv6 && tt->type == DEV_TYPE_TUN) { - delete_route_connected_v6_net(tt); + delete_route_connected_v6_net(tt, is_multipoint); } /* "store=active" is needed in Windows 8(.1) to delete the @@ -6992,7 +7006,7 @@ } void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); @@ -7012,7 +7026,7 @@ do_dns_domain_service(false, tt); } do_dns_service(false, AF_INET6, tt); - delete_route_connected_v6_net(tt); + delete_route_connected_v6_net(tt, is_multipoint); do_address_service(false, AF_INET6, tt); } else @@ -7022,7 +7036,7 @@ do_dns_domain_wmic(false, tt); } - netsh_delete_address_dns(tt, true, &gc); + netsh_delete_address_dns(tt, true, &gc, is_multipoint); } } @@ -7049,7 +7063,7 @@ if (tt->options.ip_win32_type == IPW32_SET_NETSH) { - netsh_delete_address_dns(tt, false, &gc); + netsh_delete_address_dns(tt, false, &gc, is_multipoint); } } } @@ -7170,12 +7184,13 @@ } void -close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) +close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint) { ASSERT(tt); close_tun_generic(tt); free(tt); + (void)is_multipoint; } int diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 33b9552..9716d19 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -266,7 +266,7 @@ void open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt, openvpn_net_ctx_t *ctx); -void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx); +void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx, const bool is_multipoint); void tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_guid, struct gc_arena *gc); @@ -280,7 +280,7 @@ void tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options, - openvpn_net_ctx_t *ctx); + openvpn_net_ctx_t *ctx, const bool is_multipoint); const char *guess_tuntap_dev(const char *dev, const char *dev_type, @@ -319,7 +319,7 @@ * @param ctx the networking API opaque context */ void do_ifconfig(struct tuntap *tt, const char *ifname, int tun_mtu, - const struct env_set *es, openvpn_net_ctx_t *ctx); + const struct env_set *es, openvpn_net_ctx_t *ctx, const bool is_multipoint); /** * undo_ifconfig - undo configuration of the tunnel interface @@ -754,6 +754,7 @@ } const char *tun_stat(const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc); + bool tun_name_is_fixed(const char *dev); static inline bool