From nobody Tue Aug 5 13:59:22 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4bxFQz5rx0z63GGy; Tue, 05 Aug 2025 13:59:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bxFQy3R7zz49q9; Tue, 05 Aug 2025 13:59:22 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1754402362; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=pYwhaTcxi03hVTZIcpFrGdRJun3sfWeOpsaTKYnAsh8=; b=aNHe+lyZwFVs9KZNUJGhgZBIgUWI3YjKT+QplJ7cIe64UZ4tnV/A1d25ZfbfmtY95cmchH s+5XHChIp2ECFNUxSVEOW9r2tLN2c8cWEXVW4vz2OxDybTDcziR57awbWA7oz5lE/L+PwN 8ByQPEmyixctqQm4qj6I2DCQEEm7ttf1QSRADsgA+bf/tS9UkTMFma7mwXDnXf/zTv2pl4 lst0k4MkBZPWb6MmvMVcp5gxrytLCs0UJ61sdvLBuaRX0w3ip19EMgQkcjSt0HjxWWQlvP YsJtm8StAcdkjci/icoLlVaS+Xv/c6NnSRry1jE9dW3yKG5p7D0J47dXIAGezA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1754402362; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=pYwhaTcxi03hVTZIcpFrGdRJun3sfWeOpsaTKYnAsh8=; b=pfk/l39L6B0nOBXLYiiuJAutIshC8jyZaR90vX6pNltmvB3n9TerEhn29eR1A1c0bW/dHW OX55OJEtyMg9K4F/gLPIHrXz9gKLkmrpIct42b9nDXhyYpy0mUXjZA+6/w+uOpiBzQVaJD R0l4DMlwg+/TDs1S0FI66GaUBKsP/sBTmsRSbhHsVNRyAWYRFBWXXdVbhVnc9cdKlOnSkn xMbAUuWyTS+jiQhkc6Y9U2nxppxwnyNWHf+SJIj5eAb/sB+B1AuGnt/Ukm33rhMmquB0hS 02zR61/2OBk2CSbZp9icDVO0YmQG/AJG38JjbwqzKO45xJLISXrYrEFseeGKBw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1754402362; a=rsa-sha256; cv=none; b=OD+QdAj5kOeaNKVaS5dobYR5nIsR7KYa5FrXUX89Y3grp2QmAbtfe7C3aTLLo+CDuBeayj t4a3mh0I3RmAkY+kvB/GmsgFRHrMtxvF011VXVsO12iCAbSyYoDqXbzDNry2KuFL8IssXL trKV3nJFPntyFPo8Q2Hnrbv/Uhpblm9c4Xf89pjWjitmgcDCAnIHAkvLw5N/T4bSpvEQH5 ZeNqoPn69EimV0mFjxUp7c2Dta7BngQtYOcDSOIeECdVjx0lNDFTsU7Cgh15B5BjqvhTNa GLFanki/xUk0L4AhdxHy2/K1Eyb17Esyd+uNcFlwYozOFzkI4hwe1z6xIejvCA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4bxFQy30xyzdd0; Tue, 05 Aug 2025 13:59:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 575DxMrn053001; Tue, 5 Aug 2025 13:59:22 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 575DxMCT052998; Tue, 5 Aug 2025 13:59:22 GMT (envelope-from git) Date: Tue, 5 Aug 2025 13:59:22 GMT Message-Id: <202508051359.575DxMCT052998@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: 818c85bee2c0 - stable/14 - if_ovpn: Support multihomed server configurations List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 818c85bee2c0f2f9c876df7301859903abd49520 Auto-Submitted: auto-generated The branch stable/14 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=818c85bee2c0f2f9c876df7301859903abd49520 commit 818c85bee2c0f2f9c876df7301859903abd49520 Author: Mark Johnston AuthorDate: 2025-07-25 13:15:02 +0000 Commit: Mark Johnston CommitDate: 2025-08-05 13:59:12 +0000 if_ovpn: Support multihomed server configurations In UDP server mode, openvpn implements the "multihome" option, which makes it avoid binding to an address. Instead, the server socket is bound to INADDR_ANY. Today, when configuring a new peer and setting the source address, sockaddr() returns the wildcard address, so the source address is implicitly determined by the output interface. This doesn't work as one would want if the WAN interface has multiple addresses and clients connect to non-primary addresses. Make multihome mode work properly: use the local address supplied by openvpn in preference to that of the socket. We still fetch the port number out of the socket. PR: 273664 Reviewed by: kp MFC after: 1 month Sponsored by: Stormshield Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D51498 (cherry picked from commit 05b5d56c540335ed17acf843810901338bf862d5) --- sys/net/if_ovpn.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c index 10b864f62787..e8b2cb0df1a6 100644 --- a/sys/net/if_ovpn.c +++ b/sys/net/if_ovpn.c @@ -320,6 +320,25 @@ ovpn_get_port(const struct sockaddr_storage *s) } } +static void +ovpn_set_port(struct sockaddr_storage *s, unsigned short port) +{ + switch (s->ss_family) { + case AF_INET: { + struct sockaddr_in *in = (struct sockaddr_in *)s; + in->sin_port = port; + break; + } + case AF_INET6: { + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s; + in6->sin6_port = port; + break; + } + default: + panic("Unsupported address family %d", s->ss_family); + } +} + static int ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) { @@ -333,13 +352,14 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) return (EINVAL); af = nvlist_get_number(nvl, "af"); - switch (af) { #ifdef INET case AF_INET: { struct sockaddr_in *in = (struct sockaddr_in *)sa; size_t len; const void *addr = nvlist_get_binary(nvl, "address", &len); + + memset(in, 0, sizeof(*in)); in->sin_family = af; if (len != sizeof(in->sin_addr)) return (EINVAL); @@ -354,6 +374,8 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa) struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; size_t len; const void *addr = nvlist_get_binary(nvl, "address", &len); + + memset(in6, 0, sizeof(*in6)); in6->sin6_family = af; if (len != sizeof(in6->sin6_addr)) return (EINVAL); @@ -506,7 +528,7 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl) #ifdef INET6 struct epoch_tracker et; #endif - struct sockaddr_storage remote; + struct sockaddr_storage local, remote; struct ovpn_kpeer *peer = NULL; struct file *fp = NULL; struct sockaddr *name = NULL; @@ -578,19 +600,37 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl) ret = so->so_proto->pr_sockaddr(so, &name); if (ret) goto error; + memset(&local, 0, sizeof(local)); + memcpy(&local, name, name->sa_len); + free(name, M_SONAME); + name = NULL; + if (nvlist_exists_nvlist(nvl, "local")) { + struct sockaddr_storage local1; - if (ovpn_get_port((struct sockaddr_storage *)name) == 0) { + ret = ovpn_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "local"), + &local1); + if (ret != 0) + goto error; + + /* + * openvpn doesn't provide a port here when in multihome mode, + * just steal the one the socket is bound to. + */ + if (ovpn_get_port(&local1) == 0) + ovpn_set_port(&local1, ovpn_get_port(&local)); + memcpy(&local, &local1, sizeof(local1)); + } + if (ovpn_get_port(&local) == 0) { ret = EINVAL; goto error; } - if (name->sa_family != remote.ss_family) { + if (local.ss_family != remote.ss_family) { ret = EINVAL; goto error; } - memcpy(&peer->local, name, name->sa_len); + memcpy(&peer->local, &local, sizeof(local)); memcpy(&peer->remote, &remote, sizeof(remote)); - free(name, M_SONAME); name = NULL; #ifdef INET6