From patchwork Fri Nov 28 09:38:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4645 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6c3:b0:7b1:439f:bdf with SMTP id j3csp4711785maw; Fri, 28 Nov 2025 01:38:48 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCUQ2zjVZSrJW3Yd69qncdjNI8UO0UNQRvzOYNKeIerhEeZwiDDQ2M9pgUPuO+gaQaULvT9FgkUgV/M=@openvpn.net X-Google-Smtp-Source: AGHT+IGMOpHUOHEW8Yqu4zsKDQdbWVgFRN2ZvLjhxbnSknjLR03KAW5NAgyh/QAhV5kpRQ8lcpxW X-Received: by 2002:a05:6820:2d8f:10b0:657:4884:5560 with SMTP id 006d021491bc7-65790b0795emr8098490eaf.4.1764322728067; Fri, 28 Nov 2025 01:38:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1764322728; cv=none; d=google.com; s=arc-20240605; b=M/MiO3nez+hsz4p287oE9mYEglrXbOld9D6waYSmiTH5oiqln7eDx3MTO4Gbt1UN4T aEv4BsDYy1x5bx0EyZOLs1Xct6qWw0s5+JhpjNS68AnRELQWG25HlxlRZz41qd8+MWjB 32b+1/bY7RGWGXiIVUHxbLWVy5JSHeaWPBZPgP0+D8HJnecLcwNr4LdLUOH4rAWUicaZ ke8Q1crcjzQwPPcByOIvIIMdSMoUGdDo5v8HTXvY66zHBR84299HJqqv1a8bSokZS8H9 Lf2mngLKlPtiQO4Yj0joOYpt027lbE3yYwH1rRU0/LNzes3T+duch/7O3KE4dUaK1BJt m1WQ== 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=mSjKY37NtXOral2dZjJsurpebIW78tO1vPMTerSOq0c=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=iU1HcMIDotvKv/0OwTrMIZ1Ytycv2iB9iUB/P6e1UWxhPcJRuUH3XpJk4jlU5O9H7x No8LE28JUSjEVwdu+A13ZYK+EW2R/VdP0v+oOYcOPCejDM7qVFrzjanXEm4/bQgjqahM TpBgIPAbsS17MPOOYQBY9A+U6whwiFQTu5f7NzJnBeLBsisqrusNIZtp308PP4eEJ0uO sa9Ftjl54CACXVFADNhJX3FXL8LkaX1UDeZAc//xxYkQsGvCDwiqtyqdT1N4SAq3j82V +rw1WcZ4d+L9M9NtCFuvnOHbPELN2J/In3sJr1jpe9ai+7t19ttGHVRNH3r4+/jDMRnP dM6Q==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=SJM+YymV; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=kniYSWgt; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=kOcPedKG; 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 006d021491bc7-65933f33409si442307eaf.187.2025.11.28.01.38.47 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Nov 2025 01:38:47 -0800 (PST) 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=SJM+YymV; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=kniYSWgt; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=kOcPedKG; 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=mSjKY37NtXOral2dZjJsurpebIW78tO1vPMTerSOq0c=; b=SJM+YymVxY1kybzP3PCf7H6bqc cHTWc9AeF1HXc9Y2NdjTTUs1J6UuHblnB5b5AhwpvgYJY5bCzuf5thIfR/gSeUYa42wKRa8F7C+Cq M83u9E3GLbH6C2K04L96fPJGtbjLBM3AgyLZfOwvzR4uusrKEO8vnhmtXL4pzGPxtfLc=; 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.95) (envelope-from ) id 1vOuw9-00075D-5Q; Fri, 28 Nov 2025 09:38:45 +0000 Received: from [172.30.29.66] (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.95) (envelope-from ) id 1vOuw6-000755-VN for openvpn-devel@lists.sourceforge.net; Fri, 28 Nov 2025 09:38:42 +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=FASUQLsjJ5XATcsnpm2wSaapuEpC9pM1YiKYAZWIyuE=; b=kniYSWgtwUj6K8Hl02tTUsiQ+O u3sfonowYqp/thQ5aPteH03Tio7J1lBpSlYjicKU+oucBy0TrS1/bSNGmnvWRG+KxYuvDAXMzvEWR 1olxh1ZPX2QJ9bCbnBdEAcjZEEIAg7rm71PmLs7uw0Xm8FY36/D1coBgloOFFpf/5V9Q=; 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=FASUQLsjJ5XATcsnpm2wSaapuEpC9pM1YiKYAZWIyuE=; b=kOcPedKGJ8cO+uYQOj2T7SP1iY /84UESFG5Yw/s0XkvH/NSVqwYkAdtLxhH/3jIaJFBfQ7iWS6Ujc+JksyiYzhHTFv/1IEYJ7F8MEy8 ya/udoKxgHc4Fs1mR5cG1oZpEocnkb+41R5grTbvDuObqcG8qKZG1aPlIx1KxMIzBzfo=; Received: from [193.149.48.134] (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 1vOuw5-0003Md-CU for openvpn-devel@lists.sourceforge.net; Fri, 28 Nov 2025 09:38:42 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.18.1/8.18.1) with ESMTP id 5AS9cTou003934 for ; Fri, 28 Nov 2025 10:38:29 +0100 Received: (from gert@localhost) by blue.greenie.muc.de (8.18.1/8.18.1/Submit) id 5AS9cTdB003933 for openvpn-devel@lists.sourceforge.net; Fri, 28 Nov 2025 10:38:29 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Fri, 28 Nov 2025 10:38:23 +0100 Message-ID: <20251128093829.3920-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.51.2 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-2.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 Currently, reading and processing of incoming DCO messages are decoupled: notifications are read, parsed, and the relevant information is stored in fields of dco_context_t for later processing (with t [...] 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: 1vOuw5-0003Md-CU Subject: [Openvpn-devel] [PATCH v11] dco: process messages immediately after read 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?1849965899149637138?= X-GMAIL-MSGID: =?utf-8?q?1850026469104626356?= From: Ralf Lici Currently, reading and processing of incoming DCO messages are decoupled: notifications are read, parsed, and the relevant information is stored in fields of dco_context_t for later processing (with the only exception being stats). This approach is problematic on Linux, since libnl does not allow reading a single netlink message at a time, which can result in loss of information when multiple notifications are available. This change adopts a read -> parse -> process paradigm. On Linux, processing is now invoked directly from within the parsing callback, which libnl calls for each received netlink packet. The other interfaces are adapted accordingly to unify the processing model across all platforms. On Linux, however, a DEL_PEER notification from the kernel triggers a GET_PEER request from userspace, which clutters the netlink communication logic and can lead to errors or even process exit when multiple simultaneous DEL_PEER notifications are received. To avoid this, introduce a lock that prevents requesting stats while we are still busy parsing other messages. Reported-by: Stefan Baranoff Change-Id: Iefc251cb4483c0b9fb9d6a5207db4445cd884d52 Signed-off-by: Ralf Lici Acked-by: Gert Doering Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1403 --- 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/+/1403 This mail reflects revision 11 of this Change. Acked-by according to Gerrit (reflected above): Gert Doering diff --git a/src/openvpn/dco.h b/src/openvpn/dco.h index e5e8709..cd6e32a 100644 --- a/src/openvpn/dco.h +++ b/src/openvpn/dco.h @@ -127,12 +127,13 @@ void close_tun_dco(struct tuntap *tt, openvpn_net_ctx_t *ctx); /** - * Read data from the DCO communication channel (i.e. a control packet) + * Read and process data from the DCO communication channel + * (i.e. a control packet) * * @param dco the DCO context * @return 0 on success or a negative error code otherwise */ -int dco_do_read(dco_context_t *dco); +int dco_read_and_process(dco_context_t *dco); /** * Install a DCO in the main event loop @@ -305,7 +306,7 @@ } static inline int -dco_do_read(dco_context_t *dco) +dco_read_and_process(dco_context_t *dco) { ASSERT(false); return 0; diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c index f2a89ac..25deafe 100644 --- a/src/openvpn/dco_freebsd.c +++ b/src/openvpn/dco_freebsd.c @@ -578,7 +578,7 @@ } int -dco_do_read(dco_context_t *dco) +dco_read_and_process(dco_context_t *dco) { struct ifdrv drv; uint8_t buf[4096]; @@ -689,6 +689,15 @@ nvlist_destroy(nvl); + if (dco->c->mode == CM_TOP) + { + multi_process_incoming_dco(dco); + } + else + { + process_incoming_dco(dco); + } + return 0; } diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c index 0ae30b1..5d91300 100644 --- a/src/openvpn/dco_linux.c +++ b/src/openvpn/dco_linux.c @@ -49,6 +49,15 @@ #include #include +/* When parsing multiple DEL_PEER notifications, openvpn tries to request stats + * for each DEL_PEER message (see setenv_stats). This triggers a GET_PEER + * request-reply while we are still parsing the rest of the initial + * notifications, which can lead to NLE_BUSY or even NLE_NOMEM. + * + * This basic lock ensures we don't bite our own tail by issuing a dco_get_peer + * while still busy receiving and parsing other messages. + */ +static bool __is_locked = false; /* 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 @@ -1094,29 +1103,34 @@ * message, that stores the type-specific attributes. * * the "dco" object is then filled accordingly with the information - * retrieved from the message, so that the rest of the OpenVPN code can - * react as need be. + * retrieved from the message, so that *process_incoming_dco can react + * as need be. */ + int ret; switch (gnlh->cmd) { case OVPN_CMD_PEER_GET: { - return ovpn_handle_peer(dco, attrs); + ret = ovpn_handle_peer(dco, attrs); + break; } case OVPN_CMD_PEER_DEL_NTF: { - return ovpn_handle_peer_del_ntf(dco, attrs); + ret = ovpn_handle_peer_del_ntf(dco, attrs); + break; } case OVPN_CMD_PEER_FLOAT_NTF: { - return ovpn_handle_peer_float_ntf(dco, attrs); + ret = ovpn_handle_peer_float_ntf(dco, attrs); + break; } case OVPN_CMD_KEY_SWAP_NTF: { - return ovpn_handle_key_swap_ntf(dco, attrs); + ret = ovpn_handle_key_swap_ntf(dco, attrs); + break; } default: @@ -1125,15 +1139,33 @@ return NL_STOP; } + if (ret != NL_OK) + { + return ret; + } + + if (dco->c->mode == CM_TOP) + { + multi_process_incoming_dco(dco); + } + else + { + process_incoming_dco(dco); + } + return NL_OK; } int -dco_do_read(dco_context_t *dco) +dco_read_and_process(dco_context_t *dco) { msg(D_DCO_DEBUG, __func__); - return ovpn_nl_recvmsgs(dco, __func__); + __is_locked = true; + int ret = ovpn_nl_recvmsgs(dco, __func__); + __is_locked = false; + + return ret; } static int @@ -1141,6 +1173,12 @@ { ASSERT(dco); + if (__is_locked) + { + msg(D_DCO_DEBUG, "%s: cannot request peer stats while parsing other messages", __func__); + return 0; + } + /* peer_id == -1 means "dump all peers", but this is allowed in MP mode only. * If it happens in P2P mode it means that the DCO peer was deleted and we * can simply bail out diff --git a/src/openvpn/dco_win.c b/src/openvpn/dco_win.c index ca5eedf..94f043f 100644 --- a/src/openvpn/dco_win.c +++ b/src/openvpn/dco_win.c @@ -690,7 +690,7 @@ } int -dco_do_read(dco_context_t *dco) +dco_read_and_process(dco_context_t *dco) { if (dco->ifmode != DCO_MODE_MP) { @@ -727,6 +727,15 @@ break; } + if (dco->c->mode == CM_TOP) + { + multi_process_incoming_dco(dco); + } + else + { + process_incoming_dco(dco); + } + return 0; } diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index ccb8404..1a68af4 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1243,19 +1243,11 @@ } } -static void -process_incoming_dco(struct context *c) +void +process_incoming_dco(dco_context_t *dco) { #if defined(ENABLE_DCO) && (defined(TARGET_LINUX) || defined(TARGET_FREEBSD)) - dco_context_t *dco = &c->c1.tuntap->dco; - - dco_do_read(dco); - - /* no message for us to handle - platform specific code has logged details */ - if (dco->dco_message_type == 0) - { - return; - } + struct context *c = dco->c; /* FreeBSD currently sends us removal notifcation with the old peer-id in * p2p mode with the ping timeout reason, so ignore that one to not shoot @@ -2369,7 +2361,7 @@ { if (!IS_SIG(c)) { - process_incoming_dco(c); + dco_read_and_process(&c->c1.tuntap->dco); } } } diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index a575faf..9e9b02e 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -210,6 +210,13 @@ const struct sockaddr *float_sa); /** + * Process an incoming DCO message (from kernel space). + * + * @param dco - Pointer to the structure representing the DCO context. + */ +void process_incoming_dco(dco_context_t *dco); + +/** * Write a packet to the external network interface. * @ingroup external_multiplexer * diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 2b944667..153695c 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -3263,14 +3263,12 @@ multi_signal_instance(m, mi, SIGTERM); } -bool -multi_process_incoming_dco(struct multi_context *m) +void +multi_process_incoming_dco(dco_context_t *dco) { - dco_context_t *dco = &m->top.c1.tuntap->dco; + ASSERT(dco->c->multi); - struct multi_instance *mi = NULL; - - int ret = dco_do_read(&m->top.c1.tuntap->dco); + struct multi_context *m = dco->c->multi; int peer_id = dco->dco_message_peer_id; @@ -3279,12 +3277,12 @@ */ if (peer_id < 0) { - return ret > 0; + return; } if ((peer_id < m->max_clients) && (m->instances[peer_id])) { - mi = m->instances[peer_id]; + struct multi_instance *mi = m->instances[peer_id]; set_prefix(mi); if (dco->dco_message_type == OVPN_CMD_DEL_PEER) { @@ -3325,11 +3323,6 @@ "type %d, del_peer_reason %d", peer_id, dco->dco_message_type, dco->dco_del_peer_reason); } - - dco->dco_message_type = 0; - dco->dco_message_peer_id = -1; - dco->dco_del_peer_reason = -1; - return ret > 0; } #endif /* if defined(ENABLE_DCO) */ @@ -4462,4 +4455,4 @@ return (!ipv6_net_contains_host(&ifconfig_local, o->ifconfig_ipv6_netbits, dest)); -} \ No newline at end of file +} diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index a62b07a..a44f9f2 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -305,13 +305,9 @@ /** * Process an incoming DCO message (from kernel space). * - * @param m - The single \c multi_context structure. - * - * @return - * - True, if the message was received correctly. - * - False, if there was an error while reading the message. + * @param dco - Pointer to the structure representing the DCO context. */ -bool multi_process_incoming_dco(struct multi_context *m); +void multi_process_incoming_dco(dco_context_t *dco); /**************************************************************************/ /** diff --git a/src/openvpn/multi_io.c b/src/openvpn/multi_io.c index fe72456..997951e 100644 --- a/src/openvpn/multi_io.c +++ b/src/openvpn/multi_io.c @@ -505,7 +505,7 @@ /* incoming data on DCO? */ else if (e->arg == MULTI_IO_DCO) { - multi_process_incoming_dco(m); + dco_read_and_process(&m->top.c1.tuntap->dco); } #endif /* signal received? */