From patchwork Mon Sep 28 11:37:18 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 5412 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:5189:b0:8b3:6e77:b38b with SMTP id g9csp3176292mae; Mon, 28 Sep 2026 04:37:49 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvByfZeti1W1RU/Q1+eB1ELoucqBjYYxLFVfyeP3H2KezYCnk0hOitw3UDWWJkrdaUHuWp86KbfAC8kg=@openvpn.net X-Received: by 2002:a05:6820:1504:b0:6d9:779e:4f78 with SMTP id 006d021491bc7-6d9779e6017mr1795854eaf.9.1790595469815; Mon, 28 Sep 2026 04:37:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1790595469; cv=none; d=google.com; s=arc-20260327; b=kCnJ16wEgejtSgZ5OwxvtukjvVlzU87wAhDh/OK34AcCA71SFqv6HAf/VsEKbUUVLJ wWdx8rgLLLTFf4wSlXmF4+11/0Bf8wp/lt5mypMK3PtXA6jD5zZT+NUDhtMHQLrkKFSq +r8YWCQaZMcB0W+hVinDVVCETVWVLvzUPuh0EpVl76tCnmVvTEfkB1V/RLixStA8ADa3 ekKqDt894mNhXeIx+1gR4FsV0CBPuH7jqvetWysdULoNZCSgyg0ailzOentw2VFX+DUa dDLGvFUjTlwTUWnCLZ5kHJDI9bMx5I8tcl2cm2XBkeprK7xxukdkMGtb9R57tcZxPDY9 UK4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; 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=3GUJ4Fr2S0YeYhUNCbP64j9dXH8Znqb7WZsSqVMXcME=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=CnwJ/7WW6vCX+0jU64HG7XYTM6TST5S3VjBN0KyTxTAb06g4KxsdMjFx8j4mE5jJIB K2VKoXBCwaBJwGArE6wRb+Reg0OsUKXECCvSdNG7FRBCOkfGz7sNfXmtxftlmsabOnNu 6SpOqIc/hFL9o1oVBO3se35XeIiPQ3sef2fCccFZSRkarFodu5SqM4J/pOidzqFDGb/B zJB1wMPgMsP/5solKKjyanF0Z3o4M+dw6Y1y4krtjKauzZ80i2W4wOGxQhqv2ZA98SOm qaNCse6fnKhJMgPoCYQysjzRokYoe02EPIEnsJ25RKjx9t8wrW5M/zRghvKVayF9z4dd bNXw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=ICuIfzea; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=R5+nWaPT; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=fCLxnXFy; 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 586e51a60fabf-49336ac2472si16975400fac.321.2026.09.28.04.37.49 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 28 Sep 2026 04:37:49 -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=ICuIfzea; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=R5+nWaPT; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=fCLxnXFy; 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=3GUJ4Fr2S0YeYhUNCbP64j9dXH8Znqb7WZsSqVMXcME=; b=ICuIfzeaggagUzTWHALcIz2+ZA jI1YL4n/Eewl1SQT1W5svlcU9Wp6IE6roHgH38kHGklRgXStbVIMeaqA9Yf6n/Ss8zXFFRXey2O+c CXWac1imigOsjSDoobI73fRl7+CwxCxN67ac8bK6G0MOjbtY84PHKkb9WUrc9LEBnT4Q=; 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 1xB9g2-0006HP-1Q; Mon, 28 Sep 2026 11:37:46 +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 1xB9ft-0006HD-Cx for openvpn-devel@lists.sourceforge.net; Mon, 28 Sep 2026 11:37:37 +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=za67MZAoLRwr+wGXPdM8r+3jucFB6JaI81dzzHVv444=; b=R5+nWaPTRQOKuve6vaEYLBBZuq t/NyL1N4FRgXDmsM0NAk2UfH8AN5sCtcmqG39z10759LC2g7qdqUH5yDYLrhhw9aqyJnKWdiUJg8m XVN572ToYPbm6nmsM+SGJJwoigZHeGvcs/SuuBBnYHg6N8M3ngFhbJVfpEDsHB7YOoJw=; 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=za67MZAoLRwr+wGXPdM8r+3jucFB6JaI81dzzHVv444=; b=fCLxnXFy8fENcl5tTyVTkWgvH7 rVAsJobEEzGJeymBmaFSJnxOUDgHQJA4pIPn8y6irt/ZNWF2TC5t9coer8o6mKmeyh9LxaMRN05rX +dAg9AORLc5NIvkCoY3QSPg1juuygGyKH1OMbR55M/D/Wee/URIbnDQFIiThy1S6zKd0=; Received: from [193.149.48.129] (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 1xB9fq-0000O9-Eh for openvpn-devel@lists.sourceforge.net; Mon, 28 Sep 2026 11:37:37 +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 68SBbR48032360 for ; Mon, 28 Sep 2026 13:37:27 +0200 Received: (from gert@localhost) by blue.greenie.muc.de (8.18.2/8.18.1/Submit) id 68SBbRQE032359 for openvpn-devel@lists.sourceforge.net; Mon, 28 Sep 2026 13:37:27 +0200 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Mon, 28 Sep 2026 13:37:18 +0200 Message-ID: <20260928113726.32340-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.53.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: Antonio Quartulli When a client exits due to one of the following reasons: * EEN received * AUTH_FAILED sent * RESTART sent OpenVPN will perform some minimal cleanup and will then postpone the actual instance purge by [...] 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: 1xB9fq-0000O9-Eh Subject: [Openvpn-devel] [PATCH v7] dco: remove iroute at client exit time instead of delayed exit 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: 1867529366859205735 X-GMAIL-MSGID: 1877575435304433302 From: Antonio Quartulli When a client exits due to one of the following reasons: * EEN received * AUTH_FAILED sent * RESTART sent OpenVPN will perform some minimal cleanup and will then postpone the actual instance purge by 5 seconds. If iroutes are configured for the exiting client, the actual DCO iroutes removal is also postponed. If during this time window the same client reconnects, a new instance is created (for example because --duplicate-cn is set or because the same username is provided upon authentication) and the same IP is assigned, then OpenVPN will: * create the new client instance; * attempt adding the related DCO iroutes (which will fail because EEXIST); * 5 seconds timeout fires -> execute the delayed exit routine and delete the DCO iroutes; * no iroutes exists anymore on the server despite the client being fully connected. Note that this issue is DCO specific, because without DCO OpenVPN creates virtual routes (no system routing table involved) and makes the last connecting client own them. This means that the delayed exit routine won't have any iroute to delete. With this patch we move the DCO iroutes deletion to the actual client exit time in order to avoid racing with a possible addition being executed when the client reconnects. The new flow will be: * client exits (due to EEN or timeout) * DCO iroutes are immediately deleted * client re-connects -> new instance created * DCO iroutes are added -> SUCCESS * 5 seconds timeout fires -> old instance client is fully purged * client is connected and iroutes are in place as expected This issue was reported by OpenVPN Access Server developers after observing erratic iroutes disappearance with DCO in place. Change-Id: I0ba723d12d433e6e020588b7b0c3ba10bcf8c44f GitHub: closes openvpn/OpenVPN#1040 Signed-off-by: Antonio Quartulli Acked-by: Razvan Cojocaru Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1683 --- 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/+/1683 This mail reflects revision 7 of this Change. Acked-by according to Gerrit (reflected above): Razvan Cojocaru diff --git a/src/openvpn/dco.c b/src/openvpn/dco.c index ba1c85f..6d88f6f 100644 --- a/src/openvpn/dco.c +++ b/src/openvpn/dco.c @@ -750,6 +750,8 @@ } ASSERT(TUNNEL_TYPE(c->c1.tuntap) == DEV_TYPE_TUN); + msg(D_DCO, "DCO: attempt removing iroutes from system table"); + if (c->c2.push_ifconfig_defined) { for (const struct iroute *ir = c->options.iroutes; ir; ir = ir->next) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index a8a4a07..6d85c62 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -539,6 +539,23 @@ { return false; } + + /* DCO iroutes must be removed now, because the delay introduced by this + * timer can create a race condition: + * the same client may reconnect before the old instance is purged, leading + * to DCO iroutes removal *after* reconnection, thus killing the routes + * for the new instance too. + * + * Standard/virtual iroutes (non-DCO case) are not affected because the + * last connecting client claiming the iroutes takes ownership. Therefore + * they are not removed during delayed cleanup. + */ + if (c->did_dco_iroutes) + { + c->did_dco_iroutes = false; + dco_delete_iroutes(&c->net_ctx, c); + } + tls_set_single_session(c->c2.tls_multi); update_time(); reset_coarse_timers(c); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 52364f9..3bef334 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -479,7 +479,12 @@ const struct iroute *ir; const struct iroute_ipv6 *ir6; - dco_delete_iroutes(&m->top.net_ctx, &mi->context); + /* check if DCO iroutes were already removed when scheduling a delayed exit */ + if (mi->context.did_dco_iroutes) + { + mi->context.did_dco_iroutes = false; + dco_delete_iroutes(&m->top.net_ctx, &mi->context); + } if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) { @@ -1277,6 +1282,8 @@ if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) { mi->did_iroutes = true; + /* multi_learn_in{6}_addr_t takes care of installing the DCO iroute */ + mi->context.did_dco_iroutes = true; for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) { if (ir->netbits >= 0) diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index e9e18bf..cdd02b6 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -507,6 +507,8 @@ bool did_we_daemonize; /**< Whether demonization has already * taken place. */ + bool did_dco_iroutes; /**< Whether DCO iroutes have been installed */ + struct context_persist persist; /**< Persistent %context. */ struct context_0 *c0; /**< Level 0 %context. */