From patchwork Wed Jul 16 16:29:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4312 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:d91b:b0:671:5a2c:6455 with SMTP id lg27csp280181mab; Wed, 16 Jul 2025 09:29:36 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXFpJ86N0HDksSuiJF+QUQ9mp3/YSqySTnBRotcBoc6w+rbKoqKja/fpq8RaCXQb0y1ZAIihwbZkx8=@openvpn.net X-Google-Smtp-Source: AGHT+IEZqJc9/Iw85Rte+76rbADNZTfDoeRccwumDJ9Kdtln6a/o7Cj38IrCTS/TivVwe4dEp21w X-Received: by 2002:a05:6808:3010:b0:41c:cbbc:8abe with SMTP id 5614622812f47-41cf04d9d0amr2707397b6e.31.1752683376034; Wed, 16 Jul 2025 09:29:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1752683376; cv=none; d=google.com; s=arc-20240605; b=D1UURqmQgMaO+EfrNGDi4lTXwFnA3nWmqevZ+xtUcpEUT8ONJamUj7GLkA/RmqAbJQ ipHXcllLEOHamqD9zRs2sp8C0x+NZM0eXIoiMreGo+zxU4HwufvNwwdsmi1KzrCZra3b hAT3CDTb/N/096h8SnSmzfGn3IVxplzS5CPDxSIa6FGq+JZJfFc/VZMYqL1XNepv/kfc f3DcX8mltKwl4lhdV5azEfxobQD8igiAW3h4MjsCG28UzCfHnSmkXVMWSEur8PDvrl7N l2N24uWGvRJ9JRISQEaz3IFlWyhmNW9lw1cQuwu9TkYB16tkhpM3xeAWiOB2KZkqNVqM JFfQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature; bh=ClbnmLPv04w1ZcLqqazs2+YPQBxrNnXznAWwjXkBwA8=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=NSC18VdE4OaLi2kjxRfhhBksUWJNmfWwcTcd4rC0RM90qVqbaNm4GR2w7KiWmd14GW IMao0WCWcBAsQSOj5WL5iBVyJ8ggRnAL81vXAn5mqDjoqNUFTtdSKieL8EV28HKstjD4 gLLn/Dba3TyanOWhDPu1i80mh/JR3LLpDuvE7lBTbTMFEOBJXEy1EsDTWaMCI94Icz3h bsms+Q4EBQe+hSEp5jqFgYxicloiTvPpOmSLqf9HdULjblzvPajJ58Q5sn0l7B6VBXBN wHqD6vRkPPdlqdCm7l1yTfJWbQPnJ4nw9OSNCOV0yqC8OLNsxspVrUacC9uVDRkxACDu 0BwA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=SrpPJZWt; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=UBSKzQC3; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=cfwOgAxD; 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=muc.de Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 5614622812f47-41e0b1c0eeasi193517b6e.109.2025.07.16.09.29.35 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Jul 2025 09:29:35 -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=pass header.i=@lists.sourceforge.net header.s=beta header.b=SrpPJZWt; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=UBSKzQC3; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=cfwOgAxD; 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=muc.de DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=ClbnmLPv04w1ZcLqqazs2+YPQBxrNnXznAWwjXkBwA8=; b=SrpPJZWtPcfx3Hs1sLP35vUwG/ HFGZk7BOWOHElFdZlXWMm0OFmJkA4UaSAj/pr+QVx3diU6BSh7ZZdF7Fwy0GVzdqnAMl1/Myqrl0D a1raz9U4nCjCkMdm6VycZ7BArcSn0lERoKKllwtWK+gJSjVQSOlY5USzVX/4sLg7R5R4=; 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.95) (envelope-from ) id 1uc50d-0007hx-F2; Wed, 16 Jul 2025 16:29:32 +0000 Received: from [172.30.29.66] (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.95) (envelope-from ) id 1uc50c-0007hj-6n for openvpn-devel@lists.sourceforge.net; Wed, 16 Jul 2025 16:29:31 +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:To:From:Sender:Reply-To:Cc: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=jEvvo7R1ppGfD3kdobQflE+zu49SQkgrjxU//V6Vfko=; b=UBSKzQC3DUERiFXYgF9zBvEVFi mr9VMowSajHNJoUHdHu7sQbE45Dit7FvJe3cmEc4KNy8oFJ6vL/ceCocywb1oiW197jkosEku6kg+ 5z0JM6dLbmtQOTUIA5QuGj2smQjrI3xwjr/Af6kMZ+9r3jGfbhYUFeHjJrkGZSz6q4pM=; 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:To:From:Sender:Reply-To:Cc: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=jEvvo7R1ppGfD3kdobQflE+zu49SQkgrjxU//V6Vfko=; b=cfwOgAxDwAO8nk5ZX4VCiPSz80 lYsvzhBsxWzcXN7O7wcR+zoetIDwMrHSWTK4mdDaUF7lSUpcAvMC8+7BXTZFcWi94j+tIdhr7SFju wTx2ar/uNRBY0L0fmOip/3GoqsKUUF/MsHcGnTC6wj6dCILq0UuouEz1QAfjFKPA2g/Y=; Received: from [193.149.48.143] (helo=blue.greenie.muc.de) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1uc50b-00035j-TN for openvpn-devel@lists.sourceforge.net; Wed, 16 Jul 2025 16:29:30 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.17.1.9/8.17.1.9) with ESMTP id 56GGTI54013453 for ; Wed, 16 Jul 2025 18:29:18 +0200 Received: (from gert@localhost) by blue.greenie.muc.de (8.17.1.9/8.17.1.9/Submit) id 56GGTIWU013452 for openvpn-devel@lists.sourceforge.net; Wed, 16 Jul 2025 18:29:18 +0200 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Wed, 16 Jul 2025 18:29:11 +0200 Message-ID: <20250716162917.13420-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Score: 1.3 (+) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-1.hosts.colo.sdot.me", 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: Ralf Lici When a peer changes its UDP endpoint, the DCO module emits a notification to userpace. The message is parsed and the relevant information are extracted in order to process the floating operation. Content analysis details: (1.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 1.3 RDNS_NONE Delivered to internal network by a host with no rDNS X-Headers-End: 1uc50b-00035j-TN Subject: [Openvpn-devel] [PATCH v3] dco: Add support for float notifications 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: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1837821723402930993?= X-GMAIL-MSGID: =?utf-8?q?1837821723402930993?= From: Ralf Lici When a peer changes its UDP endpoint, the DCO module emits a notification to userpace. The message is parsed and the relevant information are extracted in order to process the floating operation. Note that we preserve IPv4-mapped IPv6 addresses in userspace when receiving a pure IPv4 address from the module, otherwise openvpn wouldn't be able to retrieve the multi_instance using the transport address hash table lookup. Change-Id: I33e9272b4196c7634db2fb33a75ae4261660867f Signed-off-by: Ralf Lici Acked-by: Antonio Quartulli --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1084 This mail reflects revision 3 of this Change. Acked-by according to Gerrit (reflected above): Antonio Quartulli diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c index 22a445a..f04ebfe 100644 --- a/src/openvpn/dco_linux.c +++ b/src/openvpn/dco_linux.c @@ -768,6 +768,44 @@ return ret; } +static bool +ovpn_parse_float_addr(struct nlattr **attrs, struct sockaddr *out) +{ + if (!attrs[OVPN_A_PEER_REMOTE_PORT]) + { + msg(D_DCO, "ovpn-dco: no remote port in PEER_FLOAT_NTF message"); + return false; + } + + if (attrs[OVPN_A_PEER_REMOTE_IPV4]) + { + struct sockaddr_in *addr4 = (struct sockaddr_in *)out; + CLEAR(*addr4); + addr4->sin_family = AF_INET; + addr4->sin_port = nla_get_u16(attrs[OVPN_A_PEER_REMOTE_PORT]); + addr4->sin_addr.s_addr = nla_get_u32(attrs[OVPN_A_PEER_REMOTE_IPV4]); + return true; + } + else if (attrs[OVPN_A_PEER_REMOTE_IPV6] + && nla_len(attrs[OVPN_A_PEER_REMOTE_IPV6]) == sizeof(struct in6_addr)) + { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)out; + CLEAR(*addr6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = nla_get_u16(attrs[OVPN_A_PEER_REMOTE_PORT]); + memcpy(&addr6->sin6_addr, nla_data(attrs[OVPN_A_PEER_REMOTE_IPV6]), + sizeof(addr6->sin6_addr)); + if (attrs[OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID]) + { + addr6->sin6_scope_id = nla_get_u32(attrs[OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID]); + } + return true; + } + + msg(D_DCO, "ovpn-dco: no valid remote IP address in PEER_FLOAT_NTF message"); + return false; +} + /* This function parses any netlink message sent by ovpn-dco to userspace */ static int ovpn_handle_msg(struct nl_msg *msg, void *arg) @@ -856,6 +894,45 @@ break; } + case OVPN_CMD_PEER_FLOAT_NTF: + { + if (!attrs[OVPN_A_PEER]) + { + msg(D_DCO, "ovpn-dco: no peer in PEER_FLOAT_NTF message"); + return NL_STOP; + } + + struct nlattr *fp_attrs[OVPN_A_PEER_MAX + 1]; + if (nla_parse_nested(fp_attrs, OVPN_A_PEER_MAX, attrs[OVPN_A_PEER], + NULL)) + { + msg(D_DCO, "ovpn-dco: can't parse peer in PEER_FLOAT_NTF messsage"); + return NL_STOP; + } + + if (!fp_attrs[OVPN_A_PEER_ID]) + { + msg(D_DCO, "ovpn-dco: no peer-id in PEER_FLOAT_NTF message"); + return NL_STOP; + } + uint32_t peerid = nla_get_u32(fp_attrs[OVPN_A_PEER_ID]); + + if (!ovpn_parse_float_addr(fp_attrs, (struct sockaddr *)&dco->dco_float_peer_ss)) + { + return NL_STOP; + } + + struct gc_arena gc = gc_new(); + msg(D_DCO_DEBUG, + "ovpn-dco: received CMD_PEER_FLOAT_NTF, ifindex: %u, peer-id %u, address: %s", + ifindex, peerid, print_sockaddr((struct sockaddr *)&dco->dco_float_peer_ss, &gc)); + dco->dco_message_peer_id = (int)peerid; + dco->dco_message_type = OVPN_CMD_PEER_FLOAT_NTF; + + gc_free(&gc); + break; + } + case OVPN_CMD_KEY_SWAP_NTF: { if (!attrs[OVPN_A_KEYCONF]) diff --git a/src/openvpn/dco_linux.h b/src/openvpn/dco_linux.h index 4e441ec..676b8cd 100644 --- a/src/openvpn/dco_linux.h +++ b/src/openvpn/dco_linux.h @@ -34,6 +34,7 @@ /* Defines to avoid mismatching with other platforms */ #define OVPN_CMD_DEL_PEER OVPN_CMD_PEER_DEL_NTF #define OVPN_CMD_SWAP_KEYS OVPN_CMD_KEY_SWAP_NTF +#define OVPN_CMD_FLOAT_PEER OVPN_CMD_PEER_FLOAT_NTF typedef enum ovpn_key_slot dco_key_slot_t; typedef enum ovpn_cipher_alg dco_cipher_t; @@ -75,6 +76,7 @@ int dco_message_peer_id; int dco_message_key_id; int dco_del_peer_reason; + struct sockaddr_storage dco_float_peer_ss; uint64_t dco_read_bytes; uint64_t dco_write_bytes; } dco_context_t; diff --git a/src/openvpn/dco_win.c b/src/openvpn/dco_win.c index 2a13658..83db739 100644 --- a/src/openvpn/dco_win.c +++ b/src/openvpn/dco_win.c @@ -663,6 +663,7 @@ dco->dco_message_peer_id = dco->notif_buf.PeerId; dco->dco_message_type = dco->notif_buf.Cmd; dco->dco_del_peer_reason = dco->notif_buf.DelPeerReason; + dco->dco_float_peer_ss = dco->notif_buf.FloatAddress; } else { diff --git a/src/openvpn/dco_win.h b/src/openvpn/dco_win.h index 4513f3f..b9d93fa 100644 --- a/src/openvpn/dco_win.h +++ b/src/openvpn/dco_win.h @@ -52,6 +52,7 @@ int dco_message_peer_id; int dco_message_type; int dco_del_peer_reason; + struct sockaddr_storage dco_float_peer_ss; uint64_t dco_read_bytes; uint64_t dco_write_bytes; diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index a4f260a..0b4ceae 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1243,6 +1243,37 @@ perf_pop(); } +void +extract_dco_float_peer_addr(const uint32_t peer_id, + struct openvpn_sockaddr *out_osaddr, + const struct sockaddr *float_sa) +{ + if (float_sa->sa_family == AF_INET) + { + struct sockaddr_in *float4 = (struct sockaddr_in *)float_sa; + /* DCO treats IPv4-mapped IPv6 addresses as pure IPv4. However, we need + * to preserve the mapping, otherwise openvpn will not be able to find + * the peer by its trasnport address. + */ + if (out_osaddr->addr.sa.sa_family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED(&out_osaddr->addr.in6.sin6_addr)) + { + memcpy(&out_osaddr->addr.in6.sin6_addr.s6_addr[12], + &float4->sin_addr.s_addr, sizeof(in_addr_t)); + out_osaddr->addr.in6.sin6_port = float4->sin_port; + } + else + { + memcpy(&out_osaddr->addr.in4, float4, sizeof(struct sockaddr_in)); + } + } + else + { + struct sockaddr_in6 *float6 = (struct sockaddr_in6 *)float_sa; + memcpy(&out_osaddr->addr.in6, float6, sizeof(struct sockaddr_in6)); + } +} + static void process_incoming_dco(struct context *c) { diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 318691f..4f3d81e 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -196,6 +196,21 @@ void process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf); /** + * Transfers \c float_sa data extracted from an incoming DCO + * PEER_FLOAT_NTF to \c out_osaddr for later processing. + * + * @param peer_id - The id of the floating peer. + * @param out_osaddr - openvpn_sockaddr struct that will be filled the new + * address data + * @param float_sa - The sockaddr struct containing the data received from the + * DCO notification + * + */ +void +extract_dco_float_peer_addr(uint32_t peer_id, struct openvpn_sockaddr *out_osaddr, + const struct sockaddr *float_sa); + +/** * Write a packet to the external network interface. * @ingroup external_multiplexer * diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index a760e07..5030faa 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -3384,6 +3384,16 @@ { process_incoming_del_peer(m, mi, dco); } +#if defined(TARGET_LINUX) || defined(TARGET_WIN32) + else if (dco->dco_message_type == OVPN_CMD_FLOAT_PEER) + { + extract_dco_float_peer_addr(peer_id, &m->top.c2.from.dest, + (struct sockaddr *)&dco->dco_float_peer_ss); + ASSERT(mi->context.c2.link_sockets[0]); + multi_process_float(m, mi, mi->context.c2.link_sockets[0]); + CLEAR(dco->dco_float_peer_ss); + } +#endif /* if defined(TARGET_LINUX) || defined(TARGET_WIN32) */ else if (dco->dco_message_type == OVPN_CMD_SWAP_KEYS) { tls_session_soft_reset(mi->context.c2.tls_multi); diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 40f7519..fe9e847 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -322,7 +322,7 @@ /** * Process an incoming DCO message (from kernel space). * - * @param m - The single \c multi_context structur.e + * @param m - The single \c multi_context structure. * * @return * - True, if the message was received correctly. diff --git a/src/openvpn/ovpn_dco_linux.h b/src/openvpn/ovpn_dco_linux.h index 680d152..b3c9ff0 100644 --- a/src/openvpn/ovpn_dco_linux.h +++ b/src/openvpn/ovpn_dco_linux.h @@ -99,6 +99,7 @@ OVPN_CMD_KEY_SWAP, OVPN_CMD_KEY_SWAP_NTF, OVPN_CMD_KEY_DEL, + OVPN_CMD_PEER_FLOAT_NTF, __OVPN_CMD_MAX, OVPN_CMD_MAX = (__OVPN_CMD_MAX - 1) diff --git a/src/openvpn/ovpn_dco_win.h b/src/openvpn/ovpn_dco_win.h index 865bb38..dd6b7ce 100644 --- a/src/openvpn/ovpn_dco_win.h +++ b/src/openvpn/ovpn_dco_win.h @@ -149,7 +149,8 @@ typedef enum { OVPN_CMD_DEL_PEER, - OVPN_CMD_SWAP_KEYS + OVPN_CMD_SWAP_KEYS, + OVPN_CMD_FLOAT_PEER } OVPN_NOTIFY_CMD; typedef enum { @@ -164,6 +165,7 @@ OVPN_NOTIFY_CMD Cmd; int PeerId; OVPN_DEL_PEER_REASON DelPeerReason; + struct sockaddr_storage FloatAddress; } OVPN_NOTIFY_EVENT, * POVPN_NOTIFY_EVENT; typedef struct _OVPN_MP_DEL_PEER {