From patchwork Tue Sep 22 14:25:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Baffo X-Patchwork-Id: 5400 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6446:b0:8a0:ea1f:253a with SMTP id n6csp13340739mag; Tue, 22 Sep 2026 07:25:34 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBwWU6Md6CSqrVDU3eoyFjQ6bA3V3/7GepWVDwd4a/8jkGNnXIk6nbXXMOm0KduLWhscQ3BO34DTPbU=@openvpn.net X-Received: by 2002:a05:6820:4c08:b0:6bd:e592:2c64 with SMTP id 006d021491bc7-6ca9a847c43mr11100033eaf.23.1790087134382; Tue, 22 Sep 2026 07:25:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1790087134; cv=none; d=google.com; s=arc-20260327; b=lURRutlPgy9VCqFAPmFpTrYV0Q9PEgu8bndQKelJvYWQDZOGZ8DMcxYrdnfNZ26nvw BN0mdojCQfYWAme4HL7lMZLv17jKg9VV/LSOqS2lJiWvOwFUR/7TtPmr4+CkcibYiqv5 MpeGvKq0m/fvwk/X7bAFULH9joaCkmjwO9A4NB5qtsJCX5xfLk+0Ua+F8DlTKCgomJyE tXOR4Lt7kBj5sKl6PPhcI5Np8K6wx5XChqiBX/WyFQC7vSb0IW3nZGSBGM2K1qmCy9/c CdVK6rbLBYSPzDs31ec4NabpLyEtJHiKnxSO4+fc05u7E9RM1Zj2seoZcJq5SIljG/7w Kp+w== 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:message-id:date:to:from:dkim-signature:dkim-signature :dkim-signature:dkim-signature; bh=f3wi69AyluGP4WS4ICyIqlacp20HRJvzmRjTY0+68SE=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=JhAssIJ0V9MoDtkl0yGD6/K24r8DTD0QzzuSZOPd63lYDiQzx8Sw4bnh+FkL2dG8Mw GlgrQNMoWmFG9UtUikHsx6ixaqLIfwCLk2jOEdJqoHSLRxVrjJxPJnavO/9DM7f/s/mM eT3KI0CNpHiMMtqI08H+jw2tys/6B6dFEGJeg6mICEUwrpPtmVrtHnbFa8Wnk4MDZBVT kkPoxvnVVwdZ3D6xj4cmC/9aLsucWZl7zimqZtj670fBS/Yak+/q/u5PYy8PDUucmuvk jFFoEk15wbQ1g/5JBaSZQMPUiYFHs2YMdUXjum+plfMTJshPs+hI8Oratc+d2mM3Qp9J +OoA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=J0x3dI7D; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=g9Zlkj5n; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=WFEWs6ll; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=hJHXBaXG; 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 Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 006d021491bc7-6d1ddfff4b2si2090167eaf.24.2026.09.22.07.25.33 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Sep 2026 07:25:34 -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=J0x3dI7D; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=g9Zlkj5n; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=WFEWs6ll; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=hJHXBaXG; 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 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: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:In-Reply-To:References:List-Owner; bh=f3wi69AyluGP4WS4ICyIqlacp20HRJvzmRjTY0+68SE=; b=J0x3dI7DQxLSHyUAP7EjUI3MGz 1wzKxNE0p+nia7wk/sGW4BgkgtNdHR3apNAXa74ZCXkQq3M+cP3v6vfuGDBoPoY2Tkt9QDV8wfGKr D+Cq9omqgdDTGzSLk+mVYArszW15tV7lqqZkwCVB5RbU3Pq6k1ceNjKruMkCcROL3s/Y=; 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 1x91R3-0002XZ-Bo; Tue, 22 Sep 2026 14:25:29 +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 1x91Qt-0002XL-W2 for openvpn-devel@lists.sourceforge.net; Tue, 22 Sep 2026 14:25:21 +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:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=ZZuR28K1sZQa8aBWzy0MTx0jcdYG+4JCY2sfwQC6FSc=; b=g9Zlkj5ngzLdY/6oNnwIgX/vRJ JLm4cCs/dhSy80hFpGHddbS7pOWvyIgr2wNWaMmdvILVC+dNTZ6t4jYfWJHXiVXj35Ua7h3i1aFYm cxOzqlHA/HRmHt1AO1kLGk1qzKiWeRtA0mDIkwdnSbr0W53Qqu0Lz9FpayPSW1QKQpcM=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject:Cc:To:From :Sender:Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=ZZuR28K1sZQa8aBWzy0MTx0jcdYG+4JCY2sfwQC6FSc=; b=W FEWs6llM9OsuDlHg+VIaPiid+UlO83JICkfme2XUHwGCpDcrnRX53xYUTAsMPMVKoi/oBri1Zyv4Q kd51gCydrmsBLs4Jqe+AyYZ7XVBC1sNsNbDOZ1JC/LuzfrgDFN7xFVyGK9snAmi1KsVsbYkfuTWD/ SK2VCo9+u0xmZl14=; Received: from mout-b-112.mailbox.org ([195.10.208.42]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x91Qr-0002VE-Pj for openvpn-devel@lists.sourceforge.net; Tue, 22 Sep 2026 14:25:19 +0000 Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:b231:465::2]) (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) (No client certificate requested) by mout-b-112.mailbox.org (Postfix) with ESMTPS id 4hq2S523n4z5wkH; Tue, 22 Sep 2026 16:25:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1790087109; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=ZZuR28K1sZQa8aBWzy0MTx0jcdYG+4JCY2sfwQC6FSc=; b=hJHXBaXGTBgUNBe3yWkHqmxysaPZqKkL/AIQrqFUiLA0Gp2X0TAwKxPa46qQ8jzAfUHYCG +E7fapUC7h1uRhLkRnOfosIPqRi+ADis6tHJHKDo/AlVfecNXljWJTuRflc1nU2NkoAxZ0 lrhUntOuqWKEVlvrY80XiZl0FmTuEXkWnnebjDHh6wWY2z6hXv49wOQcF3fBqIPErUGbYL 3nY1eojvqFjdzULZ1n8hnFcE4ukBq6f+ghK9q9F+M6MFEp32a0h/4gkqGKC7f+5VJX01lQ 0ZRrdFO0xLW5UPeROlUoxadjgpPihk+BbF8FfLOCSZNvt2QvITTMaLOl4s5vug== Authentication-Results: outgoing_mbo_mout; dkim=none; spf=pass (outgoing_mbo_mout: domain of marco@mandelbit.com designates 2001:67c:2050:b231:465::2 as permitted sender) smtp.mailfrom=marco@mandelbit.com From: Marco Baffo To: openvpn-devel@lists.sourceforge.net Date: Tue, 22 Sep 2026 16:25:03 +0200 Message-ID: <20260922142505.3138388-1-marco@mandelbit.com> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4hq2S523n4z5wkH X-Spam-Score: -0.2 (/) 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: ovpn currently looks up the target interface in the network namespace associated with the netlink socket. This prevents a userspace process from controlling an ovpn interface located in another namesp [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1x91Qr-0002VE-Pj Subject: [Openvpn-devel] [PATCH ovpn net-next 1/3] ovpn: support operations on interfaces in foreign netns 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: 1877042406938866930 X-GMAIL-MSGID: 1877042406938866930 ovpn currently looks up the target interface in the network namespace associated with the netlink socket. This prevents a userspace process from controlling an ovpn interface located in another namespace. Add the optional OVPN_A_TARGET_NETNSID attribute. When present, it identifies the namespace containing the target interface relative to the namespace of the requesting Netlink socket. Resolve the ID and perform the interface lookup there. When absent, preserve the existing lookup behavior. Allow the attribute in all peer and key request policies, including peer dump requests. Signed-off-by: Marco Baffo --- Documentation/netlink/specs/ovpn.yaml | 27 ++++++++++++++++ drivers/net/ovpn/netlink-gen.c | 45 ++++++++++++++++----------- drivers/net/ovpn/netlink.c | 34 +++++++++++++++++--- include/uapi/linux/ovpn.h | 1 + 4 files changed, 84 insertions(+), 23 deletions(-) diff --git a/Documentation/netlink/specs/ovpn.yaml b/Documentation/netlink/specs/ovpn.yaml index ac50d1d7c00a6..3d8055282ebe5 100644 --- a/Documentation/netlink/specs/ovpn.yaml +++ b/Documentation/netlink/specs/ovpn.yaml @@ -341,12 +341,20 @@ attribute-sets: type: nest doc: Peer specific cipher configuration nested-attributes: keyconf + - + name: target-netnsid + type: s32 + doc: >- + ID of the network namespace containing the ovpn interface, relative to + the network namespace of the requesting Netlink socket - name: ovpn-peer-new-input subset-of: ovpn attributes: - name: ifindex + - + name: target-netnsid - name: peer nested-attributes: peer-new-input @@ -356,6 +364,8 @@ attribute-sets: attributes: - name: ifindex + - + name: target-netnsid - name: peer nested-attributes: peer-set-input @@ -365,6 +375,8 @@ attribute-sets: attributes: - name: ifindex + - + name: target-netnsid - name: peer nested-attributes: peer-del-input @@ -374,6 +386,8 @@ attribute-sets: attributes: - name: ifindex + - + name: target-netnsid - name: keyconf nested-attributes: keyconf-get @@ -383,6 +397,8 @@ attribute-sets: attributes: - name: ifindex + - + name: target-netnsid - name: keyconf nested-attributes: keyconf-swap-input @@ -392,6 +408,8 @@ attribute-sets: attributes: - name: ifindex + - + name: target-netnsid - name: keyconf nested-attributes: keyconf-del-input @@ -409,6 +427,7 @@ operations: request: attributes: - ifindex + - target-netnsid - peer - name: peer-set @@ -421,6 +440,7 @@ operations: request: attributes: - ifindex + - target-netnsid - peer - name: peer-get @@ -433,6 +453,7 @@ operations: request: attributes: - ifindex + - target-netnsid - peer reply: attributes: @@ -441,6 +462,7 @@ operations: request: attributes: - ifindex + - target-netnsid reply: attributes: - peer @@ -455,6 +477,7 @@ operations: request: attributes: - ifindex + - target-netnsid - peer - name: peer-del-ntf @@ -473,6 +496,7 @@ operations: request: attributes: - ifindex + - target-netnsid - keyconf - name: key-get @@ -485,6 +509,7 @@ operations: request: attributes: - ifindex + - target-netnsid - keyconf reply: attributes: @@ -500,6 +525,7 @@ operations: request: attributes: - ifindex + - target-netnsid - keyconf - name: key-swap-ntf @@ -519,6 +545,7 @@ operations: request: attributes: - ifindex + - target-netnsid - keyconf - diff --git a/drivers/net/ovpn/netlink-gen.c b/drivers/net/ovpn/netlink-gen.c index 92d2fdc17c2e8..7ac9de00e0206 100644 --- a/drivers/net/ovpn/netlink-gen.c +++ b/drivers/net/ovpn/netlink-gen.c @@ -126,55 +126,64 @@ const struct nla_policy ovpn_peer_set_input_nl_policy[OVPN_A_PEER_TX_ID + 1] = { }; /* OVPN_CMD_PEER_NEW - do */ -static const struct nla_policy ovpn_peer_new_nl_policy[OVPN_A_PEER + 1] = { +static const struct nla_policy ovpn_peer_new_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_new_input_nl_policy), }; /* OVPN_CMD_PEER_SET - do */ -static const struct nla_policy ovpn_peer_set_nl_policy[OVPN_A_PEER + 1] = { +static const struct nla_policy ovpn_peer_set_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_set_input_nl_policy), }; /* OVPN_CMD_PEER_GET - do */ -static const struct nla_policy ovpn_peer_get_do_nl_policy[OVPN_A_PEER + 1] = { +static const struct nla_policy ovpn_peer_get_do_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_nl_policy), }; /* OVPN_CMD_PEER_GET - dump */ -static const struct nla_policy ovpn_peer_get_dump_nl_policy[OVPN_A_IFINDEX + 1] = { +static const struct nla_policy ovpn_peer_get_dump_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, }; /* OVPN_CMD_PEER_DEL - do */ -static const struct nla_policy ovpn_peer_del_nl_policy[OVPN_A_PEER + 1] = { +static const struct nla_policy ovpn_peer_del_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_del_input_nl_policy), }; /* OVPN_CMD_KEY_NEW - do */ -static const struct nla_policy ovpn_key_new_nl_policy[OVPN_A_KEYCONF + 1] = { +static const struct nla_policy ovpn_key_new_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_nl_policy), }; /* OVPN_CMD_KEY_GET - do */ -static const struct nla_policy ovpn_key_get_nl_policy[OVPN_A_KEYCONF + 1] = { +static const struct nla_policy ovpn_key_get_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_get_nl_policy), }; /* OVPN_CMD_KEY_SWAP - do */ -static const struct nla_policy ovpn_key_swap_nl_policy[OVPN_A_KEYCONF + 1] = { +static const struct nla_policy ovpn_key_swap_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_swap_input_nl_policy), }; /* OVPN_CMD_KEY_DEL - do */ -static const struct nla_policy ovpn_key_del_nl_policy[OVPN_A_KEYCONF + 1] = { +static const struct nla_policy ovpn_key_del_nl_policy[OVPN_A_TARGET_NETNSID + 1] = { [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_TARGET_NETNSID] = { .type = NLA_S32, }, [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_del_input_nl_policy), }; @@ -186,7 +195,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_peer_new_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_peer_new_nl_policy, - .maxattr = OVPN_A_PEER, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -195,7 +204,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_peer_set_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_peer_set_nl_policy, - .maxattr = OVPN_A_PEER, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -204,14 +213,14 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_peer_get_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_peer_get_do_nl_policy, - .maxattr = OVPN_A_PEER, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { .cmd = OVPN_CMD_PEER_GET, .dumpit = ovpn_nl_peer_get_dumpit, .policy = ovpn_peer_get_dump_nl_policy, - .maxattr = OVPN_A_IFINDEX, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, { @@ -220,7 +229,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_peer_del_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_peer_del_nl_policy, - .maxattr = OVPN_A_PEER, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -229,7 +238,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_key_new_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_key_new_nl_policy, - .maxattr = OVPN_A_KEYCONF, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -238,7 +247,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_key_get_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_key_get_nl_policy, - .maxattr = OVPN_A_KEYCONF, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -247,7 +256,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_key_swap_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_key_swap_nl_policy, - .maxattr = OVPN_A_KEYCONF, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, { @@ -256,7 +265,7 @@ static const struct genl_split_ops ovpn_nl_ops[] = { .doit = ovpn_nl_key_del_doit, .post_doit = ovpn_nl_post_doit, .policy = ovpn_key_del_nl_policy, - .maxattr = OVPN_A_KEYCONF, + .maxattr = OVPN_A_TARGET_NETNSID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, }; diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index 4dad852941982..04df2c0288a5d 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -26,31 +27,52 @@ MODULE_ALIAS_GENL_FAMILY(OVPN_FAMILY_NAME); /** * ovpn_get_dev_from_attrs - retrieve the ovpn private data from the netdevice * a netlink message is targeting - * @net: network namespace where to look for the interface + * @sk: requesting netlink socket * @info: generic netlink info from the user request * @tracker: tracker object to be used for the netdev reference acquisition * * Return: the ovpn private data, if found, or an error otherwise */ static struct ovpn_priv * -ovpn_get_dev_from_attrs(struct net *net, const struct genl_info *info, +ovpn_get_dev_from_attrs(struct sock *sk, const struct genl_info *info, netdevice_tracker *tracker) { + struct net *target_net = NULL; + struct net *net = sock_net(sk); struct ovpn_priv *ovpn; struct net_device *dev; - int ifindex; + int ifindex, target_id; if (GENL_REQ_ATTR_CHECK(info, OVPN_A_IFINDEX)) return ERR_PTR(-EINVAL); ifindex = nla_get_u32(info->attrs[OVPN_A_IFINDEX]); + if (info->attrs[OVPN_A_TARGET_NETNSID]) { + /* Target netns IDs are relative to the requesting Netlink socket */ + target_id = nla_get_s32(info->attrs[OVPN_A_TARGET_NETNSID]); + target_net = rtnl_get_net_ns_capable(sk, target_id); + if (IS_ERR(target_net)) { + if (PTR_ERR(target_net) == -EACCES) + NL_SET_ERR_MSG_MOD(info->extack, + "insufficient permission for target network namespace"); + else + NL_SET_ERR_MSG_MOD(info->extack, + "invalid target network namespace ID"); + NL_SET_BAD_ATTR(info->extack, + info->attrs[OVPN_A_TARGET_NETNSID]); + return ERR_CAST(target_net); + } + net = target_net; + } + rcu_read_lock(); dev = dev_get_by_index_rcu(net, ifindex); if (!dev) { rcu_read_unlock(); NL_SET_ERR_MSG_MOD(info->extack, "ifindex does not match any interface"); + put_net(target_net); return ERR_PTR(-ENODEV); } @@ -59,12 +81,14 @@ ovpn_get_dev_from_attrs(struct net *net, const struct genl_info *info, NL_SET_ERR_MSG_MOD(info->extack, "specified interface is not ovpn"); NL_SET_BAD_ATTR(info->extack, info->attrs[OVPN_A_IFINDEX]); + put_net(target_net); return ERR_PTR(-EINVAL); } ovpn = netdev_priv(dev); netdev_hold(dev, tracker, GFP_ATOMIC); rcu_read_unlock(); + put_net(target_net); return ovpn; } @@ -73,7 +97,7 @@ int ovpn_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info) { netdevice_tracker *tracker = (netdevice_tracker *)&info->user_ptr[1]; - struct ovpn_priv *ovpn = ovpn_get_dev_from_attrs(genl_info_net(info), + struct ovpn_priv *ovpn = ovpn_get_dev_from_attrs(NETLINK_CB(skb).sk, info, tracker); if (IS_ERR(ovpn)) @@ -738,7 +762,7 @@ int ovpn_nl_peer_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) struct ovpn_priv *ovpn; struct ovpn_peer *peer; - ovpn = ovpn_get_dev_from_attrs(sock_net(cb->skb->sk), info, &tracker); + ovpn = ovpn_get_dev_from_attrs(NETLINK_CB(cb->skb).sk, info, &tracker); if (IS_ERR(ovpn)) return PTR_ERR(ovpn); diff --git a/include/uapi/linux/ovpn.h b/include/uapi/linux/ovpn.h index 06690090a1a95..3fdf24182df43 100644 --- a/include/uapi/linux/ovpn.h +++ b/include/uapi/linux/ovpn.h @@ -85,6 +85,7 @@ enum { OVPN_A_IFINDEX = 1, OVPN_A_PEER, OVPN_A_KEYCONF, + OVPN_A_TARGET_NETNSID, __OVPN_A_MAX, OVPN_A_MAX = (__OVPN_A_MAX - 1) From patchwork Tue Sep 22 14:25:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Baffo X-Patchwork-Id: 5399 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6446:b0:8a0:ea1f:253a with SMTP id n6csp13340732mag; Tue, 22 Sep 2026 07:25:34 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBw/QSDnccmicLEgBWABTQU2DYki6L8PqIkMcaFRml8ImE8d4Sq7ldWUTVnQ2pGw/albqC+RIJRsRLI=@openvpn.net X-Received: by 2002:a05:6871:3747:b0:48f:e0f6:bd4a with SMTP id 586e51a60fabf-48fe0f6ccf9mr909819fac.31.1790087134179; Tue, 22 Sep 2026 07:25:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1790087134; cv=none; d=google.com; s=arc-20260327; b=hJKRevfZLVhrYX552MDmG7krlDMP97wip1PrHJm8BaHYSs49PgRlxRzzxqklIMhh3p m1PJNrUVSOmf/v7pDBO3JtbOGbyS3v7Awfc4csZjCcJu7M2lqTeFaGujdJsFAv/7FNYL j6l0Fdm83tV7smj/KsUL0oAC5PlkU/ASUxhVTvPyc6c8kCOhF2+cgInakxdbhiF1rK15 oHZ5UEVDCCMEfc3kwYwq93TJHqvLW1tws+x3Q57dPgRVFbhJkIU+1SENUuG/QGnbmpH8 v/QgfhW4sL9Tl39Vp5VBcfEOQeMrW39PpTxkWYiRi1QRo6Y7mGB0YswI1h9xmvAaj9gd Ygvw== 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:dkim-signature; bh=8ILjLKVOxzKN8ExA+i9DN4hsiC2nUv+iAYshu6FS43A=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=sKW9ySRwb6iBfRV+aOhw/kUZhrlKcwJAzxc8e+IIhFHD4SfJzhP1NWrXShs6kIDFgy 8GnT3OGkJzhyJdkPDmP10PjvHraIuW9j6mGkNW1QoZFjQGKBzcPHCwo+B8VQXg52gQmJ G70132VSz+9IvtXKFBFqTc3jum1kiyuJZtrzGZfYa81YP4ow1Vup8E7g8Tt7Lmr4sXY3 dE/u1vzVIjaVQOfFjFemz7c57lecYk9Ikw7oKx9fQHzdI/pmOp99+l/81bKtSP1C28bD y/UPki6cgqFMwrgeeAAKwJ+CEydEOwkjB1za7Uq6AKiWBOnwoLT7UhJ5c5BLeIyKG1gr lqEg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=NQWtsNPH; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=Pgq9+Lix; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=IkEMrRid; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=BfvoBd0h; 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 Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 586e51a60fabf-48fbf4b7723si1914243fac.215.2026.09.22.07.25.33 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Sep 2026 07:25:34 -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=NQWtsNPH; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=Pgq9+Lix; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=IkEMrRid; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=BfvoBd0h; 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 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=8ILjLKVOxzKN8ExA+i9DN4hsiC2nUv+iAYshu6FS43A=; b=NQWtsNPHLheMvKjm2lk61JUQU5 tnM+drlYgdAttEmteghYhCl6cdKpJWl16/ZUK7K4tqq0QzMlfJLO3Y+8DgElTC/znq6Dan6vcbeK5 WRGZhhmT5U/bo/WcDqKJc2nrN4WZrO9amyf6eKfyneb5k2ygdLDsnM04XfhIlbPfphHQ=; 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 1x91R6-000640-Kt; Tue, 22 Sep 2026 14:25:30 +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 1x91Qw-00063l-Un for openvpn-devel@lists.sourceforge.net; Tue, 22 Sep 2026 14:25:21 +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:Cc:To:From:Sender:Reply-To: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=OFB80b2B5lThtSDxDFyJA6YeBrOiQJawIQIHrzvUi5Y=; b=Pgq9+Lix8ENZZiEG1+gjtmLVqy 3NB2GUp9spHJhDN4u4EMlp3WT/NjJtzoiVzsCyA3vfhNzD81B9cafhk1SKjTsdnvzpxV40o6hDNGZ uDnrFGsDeFQH08GlvbfTA6RVoaHrHGk2mLRXOZuvqL41rj0PafE5wbkO31OWDcIvbZMk=; 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:Cc:To:From:Sender:Reply-To: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=OFB80b2B5lThtSDxDFyJA6YeBrOiQJawIQIHrzvUi5Y=; b=IkEMrRid5xJW3NyqKFmW4nsdK8 BdaEzQHix1e60qJfra7jBz5/x6Q1HJoKCv8AShhVgBAiOKK16HRyLHBVJSMubeBECj9oq17qIHdWf 0FHFucLLfdtukJ5QjA0Lk0dF6OYfeRXJ8x0VI++7hmLGe2Bf38vaRTuCsc8R+WJupLLE=; Received: from mout-b-110.mailbox.org ([195.10.208.55]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x91Qs-0005bU-KP for openvpn-devel@lists.sourceforge.net; Tue, 22 Sep 2026 14:25:20 +0000 Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:b231:465::2]) (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) (No client certificate requested) by mout-b-110.mailbox.org (Postfix) with ESMTPS id 4hq2S65tstzNlxK; Tue, 22 Sep 2026 16:25:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1790087110; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OFB80b2B5lThtSDxDFyJA6YeBrOiQJawIQIHrzvUi5Y=; b=BfvoBd0ha3Ed8wdWf4Uplj1I/EMylKfJQPT1zXZwu6wS+ySw7zqHpiOuj6aJw6EyzknjoI LlBrfEV16RHhA1JwVgO2CAUv+UOeySf8+LdUGGKrhI/MtwLCcdcn5Dmw67T2CcnA8eQop9 V9/k+lriScs0YaAw1O85UPJcTnmjsCQZUnsLtUN8BXc/pNydhRX7qabrPyT/FMKDddYb2D 9MU5iJMArFRQHsAb7fQjFgg0wqJFJjcarsmSHUAPeZGVQcCui5edA4Bdg2gr6EnmfLC74W BthajIqCpdwljqfkEuMJimEUZmAk4x6CutzkMPeFpLljyn87Ei+bSdYzt+jv7w== Authentication-Results: outgoing_mbo_mout; dkim=none; spf=pass (outgoing_mbo_mout: domain of marco@mandelbit.com designates 2001:67c:2050:b231:465::2 as permitted sender) smtp.mailfrom=marco@mandelbit.com From: Marco Baffo To: openvpn-devel@lists.sourceforge.net Date: Tue, 22 Sep 2026 16:25:04 +0200 Message-ID: <20260922142505.3138388-2-marco@mandelbit.com> In-Reply-To: <20260922142505.3138388-1-marco@mandelbit.com> References: <20260922142505.3138388-1-marco@mandelbit.com> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4hq2S65tstzNlxK X-Spam-Score: -0.2 (/) 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: vpn notifications are multicast in the network namespace of the peer transport socket, but carry an ifindex that is only meaningful in the ovpn device namespace. If the two namespaces differ, listener [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1x91Qs-0005bU-KP Subject: [Openvpn-devel] [PATCH ovpn net-next 2/3] ovpn: send notifications in the device netns 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: 1877042406647168295 X-GMAIL-MSGID: 1877042406647168295 vpn notifications are multicast in the network namespace of the peer transport socket, but carry an ifindex that is only meaningful in the ovpn device namespace. If the two namespaces differ, listeners resolve it to an unrelated interface, as ifindexes are numbered per netns. Multicast notifications in the device namespace instead. This also avoids depending on the transport socket when sending a notification. Fixes: 89d3c0e4612a ("ovpn: kill key and notify userspace in case of IV exhaustion") Fixes: a215d253c17a ("ovpn: notify userspace when a peer is deleted") Fixes: c841b676da98 ("ovpn: notify userspace on client float event") Signed-off-by: Marco Baffo --- drivers/net/ovpn/netlink.c | 44 +++++--------------------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index 04df2c0288a5d..5c94d34219c73 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -1188,7 +1188,6 @@ int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info) */ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer) { - struct ovpn_socket *sock; struct sk_buff *msg; struct nlattr *attr; int ret = -EMSGSIZE; @@ -1221,23 +1220,12 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer) goto err_cancel_msg; nla_nest_end(msg, attr); - genlmsg_end(msg, hdr); - - rcu_read_lock(); - sock = rcu_dereference(peer->sock); - if (!sock) { - ret = -EINVAL; - goto err_unlock; - } - genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0, - OVPN_NLGRP_PEERS, GFP_ATOMIC); - rcu_read_unlock(); + genlmsg_multicast_netns(&ovpn_nl_family, dev_net(peer->ovpn->dev), msg, + 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); return 0; -err_unlock: - rcu_read_unlock(); err_cancel_msg: genlmsg_cancel(msg, hdr); err_free_msg: @@ -1255,7 +1243,6 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer) int ovpn_nl_peer_float_notify(struct ovpn_peer *peer, const struct sockaddr_storage *ss) { - struct ovpn_socket *sock; struct sockaddr_in6 *sa6; struct sockaddr_in *sa; struct sk_buff *msg; @@ -1305,21 +1292,11 @@ int ovpn_nl_peer_float_notify(struct ovpn_peer *peer, nla_nest_end(msg, attr); genlmsg_end(msg, hdr); - - rcu_read_lock(); - sock = rcu_dereference(peer->sock); - if (!sock) { - ret = -EINVAL; - goto err_unlock; - } - genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, + genlmsg_multicast_netns(&ovpn_nl_family, dev_net(peer->ovpn->dev), msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); - rcu_read_unlock(); return 0; -err_unlock: - rcu_read_unlock(); err_cancel_msg: genlmsg_cancel(msg, hdr); err_free_msg: @@ -1336,7 +1313,6 @@ int ovpn_nl_peer_float_notify(struct ovpn_peer *peer, */ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id) { - struct ovpn_socket *sock; struct nlattr *k_attr; struct sk_buff *msg; int ret = -EMSGSIZE; @@ -1370,20 +1346,10 @@ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id) nla_nest_end(msg, k_attr); genlmsg_end(msg, hdr); - - rcu_read_lock(); - sock = rcu_dereference(peer->sock); - if (!sock) { - ret = -EINVAL; - goto err_unlock; - } - genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0, - OVPN_NLGRP_PEERS, GFP_ATOMIC); - rcu_read_unlock(); + genlmsg_multicast_netns(&ovpn_nl_family, dev_net(peer->ovpn->dev), msg, + 0, OVPN_NLGRP_PEERS, GFP_ATOMIC); return 0; -err_unlock: - rcu_read_unlock(); err_cancel_msg: genlmsg_cancel(msg, hdr); err_free_msg: From patchwork Tue Sep 22 14:25:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Baffo X-Patchwork-Id: 5401 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6446:b0:8a0:ea1f:253a with SMTP id n6csp13340745mag; Tue, 22 Sep 2026 07:25:34 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBzkapVDl+SVA1BhACLK8fFup/DyujNHZHhozBV+6xPBJCcfjq6Q02NSGxGo/OK7mPwvwbbYd3uFXyY=@openvpn.net X-Received: by 2002:a05:6820:1515:b0:6c9:80d9:5f5 with SMTP id 006d021491bc7-6ca9c94f29bmr11926409eaf.54.1790087134711; Tue, 22 Sep 2026 07:25:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1790087134; cv=none; d=google.com; s=arc-20260327; b=Jvcc1pb5IFlvLntxgJxdvD8VFArqWCkNEoslGO0oJ7a7Y2fhcyIl5ojrwhJc5dZScz x1SEVNF98eHuxbS2PvTTNbP0/I+FcxU+RXobLz8uffRHrSieBK9xa1TnrKr4oSG7MSiA MHkWp9qSeFexP+tx2hVjNIA2MXdgcrQ7zZYA4qHGMYYT5i5IlA6TyIVNKdb0gRfzfZ85 xjWVbVqWpYghAFiznUxrK2lOFaftm0cHTP62+2HnPtRNEAW38EilVW5YBrB0HGTXpLuv SfNrS9J5ETXOktDKITsyQOMa6pZrT8QNeq1trU9iI45i4HLFHguQUs7rP37Eb+rLogm+ cMAQ== 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:dkim-signature; bh=s4DYg4+HkBcul385YtRFEnsEY5aZcWy5V4GVQH/OuLE=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=Y2e7xBIMXj1VELPPbdH69zOorUnmHxuI58E7PuhxGIw+RjUCFHMI1LXITNQQH4cZNf UMdeunUNLXlVSwxgj49ufkQHBb6wSRjDa7d6Cw/wWugX/JYs5ZEhbL3ibFvQK23tK4iz pMcOg3AQm17PS9BFeYdS+8dNp6Q1kM1qWh1NnT4ISoQ9gJFykJ9kAKoRaNV2Lqn3doSm HWZ96cj02l/N6szMm2jySf7G14FVkq6HwTWTORqGfClDPJDjxJCpvVqq9MJSEe3McYw9 Dyep6kbiyLqGXkWvX2M36e2n3mn1bGOL3pBIE7+pXTv+ZbEL5Y9blVyl51HPwkzxktd+ LYsA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=iwrhw+WQ; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=JkAoBOn7; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=eMfg929q; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b="lru9UP/6"; 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 Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 586e51a60fabf-48fbfae5c00si1890825fac.274.2026.09.22.07.25.34 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Sep 2026 07:25:34 -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=iwrhw+WQ; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=JkAoBOn7; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=eMfg929q; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b="lru9UP/6"; 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 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=s4DYg4+HkBcul385YtRFEnsEY5aZcWy5V4GVQH/OuLE=; b=iwrhw+WQfCObxTfRdu5J88aHHa ibkaCa781X+pufTROlgvgucB9cdaiwo+Tbu7K+rg5pRHprTQsqc5E4JquNvrOPwVCiA0e9gUDYVMZ 6dxsuL8SeeH+Wxt/HhzKkHDOQ/ka/Vb+JVN2X6azxarGrqAyoI10y7ODB49HgoUBeAFs=; 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 1x91R4-0000om-Na; Tue, 22 Sep 2026 14:25:31 +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 1x91Qv-0000nt-Ar for openvpn-devel@lists.sourceforge.net; Tue, 22 Sep 2026 14:25:22 +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:Cc:To:From:Sender:Reply-To: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=NuWFKiWa11wHoN5Ze5PjQ6Zu35DOMLokSV4aSPNjjY0=; b=JkAoBOn7NTaVsHGWtJ6p9uJBU0 j8NDt1WPNeQkust+nkxkg992oFFWW+iBobt912bUJHOXHEz0hy3P4SfxTEg+vDbzIqIePuE0kkMJp 8WXiY3vmfRHPGOCEyYlqcDN0dom8GNV/a/7gvq42ojXsg1j50l7DZVxUpu0YJaSQZCZ8=; 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:Cc:To:From:Sender:Reply-To: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=NuWFKiWa11wHoN5Ze5PjQ6Zu35DOMLokSV4aSPNjjY0=; b=eMfg929qhOQMgpMg9OMgfB0jUd 3c+nz0Lbdd0K1ocYDaOv8j1PioR6YFoZfb6CcXnne4YGc9lve5qTNKbJLIiobsOfrqk57/FAgxSaH nFZfTNHhUY6kE6Teexdq7WZs0XqhGw3ovXORY9FG8LjOJCUmmiUrwGK6AzKshyQJMb+M=; Received: from mout-b-106.mailbox.org ([195.10.208.46]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x91Qu-0005bZ-7B for openvpn-devel@lists.sourceforge.net; Tue, 22 Sep 2026 14:25:22 +0000 Received: from smtp2.mailbox.org (smtp2.mailbox.org [10.196.197.2]) (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) (No client certificate requested) by mout-b-106.mailbox.org (Postfix) with ESMTPS id 4hq2S833tyzNlZ7; Tue, 22 Sep 2026 16:25:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1790087112; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NuWFKiWa11wHoN5Ze5PjQ6Zu35DOMLokSV4aSPNjjY0=; b=lru9UP/6Di5BTDFdUAr7CO/nnS1DoyiIAlr2FtBoo24D+nqg8A61eac1uebsP8KFBa6FQb elkZ6E0jSTU0nbeg3p8Xf0FSqnp2scWfZBhKS7qdbVZx1E2YYopDzfbzsnqJvZxuth2HEr F94jB4h8Mm+hPcc7dRK96HLHpztdMTVKR0BZCiJg8Ywe9lMyEn5HHYEdiFhb5/XjlhA/0/ ZAbB8mnPQWohkIE2Rp02FdvXq8p44Q29net7aBvM81aZNnRXFbCNh/Yf9KwV2sQXVryKwL UOHIPYS0zmzc09/YVzFjzCld73iR2FQp9QZv6utS1eeP1uEwFCbdpPBb/mHxPw== From: Marco Baffo To: openvpn-devel@lists.sourceforge.net Date: Tue, 22 Sep 2026 16:25:05 +0200 Message-ID: <20260922142505.3138388-3-marco@mandelbit.com> In-Reply-To: <20260922142505.3138388-1-marco@mandelbit.com> References: <20260922142505.3138388-1-marco@mandelbit.com> MIME-Version: 1.0 X-Spam-Score: -0.2 (/) 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: Extend ovpn-cli with -n to resolve an interface in a named network namespace and include OVPN_A_TARGET_NETNSID in peer and key requests. Use -n for existing peer and key operations that do not create transport sockets, exercising foreign-netns requests throughout the test suite. Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1x91Qu-0005bZ-7B Subject: [Openvpn-devel] [PATCH ovpn net-next 3/3] selftests: ovpn: test operations in a foreign netns 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: 1877042407313188465 X-GMAIL-MSGID: 1877042407313188465 Extend ovpn-cli with -n to resolve an interface in a named network namespace and include OVPN_A_TARGET_NETNSID in peer and key requests. Use -n for existing peer and key operations that do not create transport sockets, exercising foreign-netns requests throughout the test suite. Signed-off-by: Marco Baffo --- tools/testing/selftests/net/ovpn/common.sh | 8 +- tools/testing/selftests/net/ovpn/ovpn-cli.c | 265 +++++++++++++++++- .../selftests/net/ovpn/test-close-socket.sh | 4 +- tools/testing/selftests/net/ovpn/test-mark.sh | 6 +- tools/testing/selftests/net/ovpn/test.sh | 50 ++-- 5 files changed, 288 insertions(+), 45 deletions(-) diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh index 2d844eb3aa6e3..4f2510fb6d7f7 100644 --- a/tools/testing/selftests/net/ovpn/common.sh +++ b/tools/testing/selftests/net/ovpn/common.sh @@ -221,7 +221,7 @@ ovpn_add_peer() { ${OVPN_UDP_PEERS_FILE} for p in $(seq 1 ${OVPN_NUM_PEERS}); do - ip netns exec "${server_ns}" ${OVPN_CLI} \ + "${OVPN_CLI}" -n "${server_ns}" \ new_key tun0 ${p} 1 0 ${OVPN_ALG} 0 \ data64.key done @@ -244,7 +244,7 @@ ovpn_add_peer() { ip netns exec "${peer_ns}" ${OVPN_CLI} new_peer \ tun${1} ${PEER_ID} ${TX_ID} ${LPORT} ${RADDR} \ ${RPORT} - ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${1} \ + "${OVPN_CLI}" -n "${peer_ns}" new_key tun${1} \ ${PEER_ID} 1 0 ${OVPN_ALG} 1 data64.key fi else @@ -252,8 +252,8 @@ ovpn_add_peer() { (ip netns exec "${server_ns}" ${OVPN_CLI} listen tun0 \ 1 ${M_ID} ${OVPN_TCP_PEERS_FILE} && { for p in $(seq 1 ${OVPN_NUM_PEERS}); do - ip netns exec "${server_ns}" \ - ${OVPN_CLI} new_key tun0 ${p} \ + "${OVPN_CLI}" -n "${server_ns}" \ + new_key tun0 ${p} \ 1 0 ${OVPN_ALG} 0 data64.key done }) & diff --git a/tools/testing/selftests/net/ovpn/ovpn-cli.c b/tools/testing/selftests/net/ovpn/ovpn-cli.c index f4effa7580c0f..a0e4f2f581b59 100644 --- a/tools/testing/selftests/net/ovpn/ovpn-cli.c +++ b/tools/testing/selftests/net/ovpn/ovpn-cli.c @@ -6,6 +6,7 @@ * Author: Antonio Quartulli */ +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -121,6 +123,8 @@ struct ovpn_ctx { unsigned int ifindex; char ifname[IFNAMSIZ]; + const char *target_netns_name; + int target_netnsid; enum ovpn_mode mode; bool mode_set; @@ -224,6 +228,10 @@ static struct nl_ctx *nl_ctx_alloc_flags(struct ovpn_ctx *ovpn, int cmd, if (ovpn->ifindex > 0) NLA_PUT_U32(ctx->nl_msg, OVPN_A_IFINDEX, ovpn->ifindex); + if (ovpn->target_netnsid >= 0) + NLA_PUT_S32(ctx->nl_msg, OVPN_A_TARGET_NETNSID, + ovpn->target_netnsid); + return ctx; nla_put_failure: err_msg: @@ -1365,12 +1373,195 @@ static int ovpn_rt_send(struct nlmsghdr *payload, pid_t peer, return ret; } +static int ovpn_parse_netnsid(struct nlmsghdr *msg, void *arg) +{ + struct rtgenmsg *gen; + struct rtattr *attr; + int len; + + if (msg->nlmsg_type != RTM_NEWNSID || + msg->nlmsg_len < NLMSG_LENGTH(sizeof(*gen))) + return -EINVAL; + + gen = NLMSG_DATA(msg); + len = NLMSG_PAYLOAD(msg, sizeof(*gen)); + attr = (struct rtattr *)((char *)gen + NLMSG_ALIGN(sizeof(*gen))); + + for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { + if (attr->rta_type != NETNSA_NSID) + continue; + + if (RTA_PAYLOAD(attr) < sizeof(int32_t)) + return -EINVAL; + + memcpy(arg, RTA_DATA(attr), sizeof(int32_t)); + return 0; + } + + return -ENOENT; +} + +struct ovpn_netns_req { + struct nlmsghdr n; + struct rtgenmsg g; + char buf[64]; +}; + +static int ovpn_get_netnsid(int netns_fd, int *netnsid) +{ + struct ovpn_netns_req req = { 0 }; + uint32_t fd = netns_fd; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.g)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETNSID; + req.g.rtgen_family = AF_UNSPEC; + + if (ovpn_addattr(&req.n, sizeof(req), NETNSA_FD, &fd, + sizeof(fd)) < 0) + return -EMSGSIZE; + + *netnsid = NETNSA_NSID_NOT_ASSIGNED; + return ovpn_rt_send(&req.n, 0, 0, ovpn_parse_netnsid, netnsid); +} + +static int ovpn_assign_netnsid(int netns_fd) +{ + /* NETNSA_NSID_NOT_ASSIGNED asks the kernel to allocate an NSID. */ + int32_t netnsid = NETNSA_NSID_NOT_ASSIGNED; + struct ovpn_netns_req req = { 0 }; + uint32_t fd = netns_fd; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.g)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWNSID; + req.g.rtgen_family = AF_UNSPEC; + + if (ovpn_addattr(&req.n, sizeof(req), NETNSA_NSID, &netnsid, + sizeof(netnsid)) < 0 || + ovpn_addattr(&req.n, sizeof(req), NETNSA_FD, &fd, + sizeof(fd)) < 0) + return -EMSGSIZE; + + return ovpn_rt_send(&req.n, 0, 0, NULL, NULL); +} + +/* Get the target NSID relative to the current netns, assigning one if necessary. */ +static int ovpn_get_or_assign_netnsid(int netns_fd) +{ + int netnsid, ret; + + ret = ovpn_get_netnsid(netns_fd, &netnsid); + if (ret < 0) + return ret; + + if (netnsid >= 0) + return netnsid; + + ret = ovpn_assign_netnsid(netns_fd); + if (ret < 0 && ret != -EEXIST) + return ret; + + ret = ovpn_get_netnsid(netns_fd, &netnsid); + if (ret < 0) + return ret; + + if (netnsid < 0) + return -ENOENT; + + return netnsid; +} + +static int ovpn_parse_ifindex(struct nlmsghdr *msg, void *arg) +{ + struct ifinfomsg *ifinfo; + + if (msg->nlmsg_type != RTM_NEWLINK || + msg->nlmsg_len < NLMSG_LENGTH(sizeof(*ifinfo))) + return -EINVAL; + + ifinfo = NLMSG_DATA(msg); + if (ifinfo->ifi_index <= 0) + return -EINVAL; + + *(unsigned int *)arg = ifinfo->ifi_index; + + return 0; +} + struct ovpn_link_req { struct nlmsghdr n; struct ifinfomsg i; char buf[256]; }; +static int ovpn_get_ifindex(int netnsid, const char *ifname, + unsigned int *ifindex) +{ + struct ovpn_link_req req = { 0 }; + int32_t id = netnsid; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETLINK; + req.i.ifi_family = AF_UNSPEC; + + if (ovpn_addattr(&req.n, sizeof(req), IFLA_TARGET_NETNSID, &id, + sizeof(id)) < 0 || + ovpn_addattr(&req.n, sizeof(req), IFLA_IFNAME, ifname, + strlen(ifname) + 1) < 0) + return -EMSGSIZE; + + return ovpn_rt_send(&req.n, 0, 0, ovpn_parse_ifindex, ifindex); +} + +#define NETNS_RUN_DIR "/var/run/netns" + +static int ovpn_resolve_netns(struct ovpn_ctx *ovpn) +{ + int len, target_fd, ret; + char path[PATH_MAX]; + + if (!ovpn->target_netns_name[0] || + strchr(ovpn->target_netns_name, '/')) { + fprintf(stderr, "invalid network namespace name: %s\n", + ovpn->target_netns_name); + return -EINVAL; + } + + len = snprintf(path, sizeof(path), "%s/%s", NETNS_RUN_DIR, + ovpn->target_netns_name); + if (len < 0 || len >= (int)sizeof(path)) + return -ENAMETOOLONG; + + target_fd = open(path, O_RDONLY); + if (target_fd < 0) { + ret = errno; + fprintf(stderr, "cannot open network namespace %s: %s\n", + ovpn->target_netns_name, strerror(ret)); + return -ret; + } + + ovpn->target_netnsid = ovpn_get_or_assign_netnsid(target_fd); + if (ovpn->target_netnsid < 0) { + ret = ovpn->target_netnsid; + fprintf(stderr, "cannot resolve network namespace ID for %s\n", + ovpn->target_netns_name); + goto out; + } + + ret = ovpn_get_ifindex(ovpn->target_netnsid, ovpn->ifname, + &ovpn->ifindex); + if (ret < 0) { + fprintf(stderr, "cannot find interface %s in namespace %s\n", + ovpn->ifname, ovpn->target_netns_name); + } +out: + close(target_fd); + + return ret; +} + static int ovpn_new_iface(struct ovpn_ctx *ovpn) { struct rtattr *linkinfo, *data; @@ -1662,8 +1853,10 @@ static int ovpn_listen_mcast(void) static void usage(const char *cmd) { fprintf(stderr, - "Usage %s [arguments..]\n", + "Usage %s [-n ] [arguments..]\n", cmd); + fprintf(stderr, + "\t-n netns: run peer/key operations on an interface in the named network namespace\n"); fprintf(stderr, "where can be one of the following\n\n"); fprintf(stderr, "* new_iface [mode]: create new ovpn interface\n"); @@ -1968,6 +2161,26 @@ static enum ovpn_cmd ovpn_parse_cmd(const char *cmd) return CMD_INVALID; } +static bool ovpn_cmd_supports_target_netns(enum ovpn_cmd cmd) +{ + switch (cmd) { + case CMD_LISTEN: + case CMD_CONNECT: + case CMD_NEW_PEER: + case CMD_NEW_MULTI_PEER: + case CMD_SET_PEER: + case CMD_DEL_PEER: + case CMD_GET_PEER: + case CMD_NEW_KEY: + case CMD_DEL_KEY: + case CMD_GET_KEY: + case CMD_SWAP_KEYS: + return true; + default: + return false; + } +} + /* Send process to background and waits for signal. * * This helper is called at the end of commands @@ -2023,6 +2236,7 @@ static int ovpn_run_cmd(struct ovpn_ctx *ovpn) } peer_ctx.ifindex = ovpn->ifindex; + peer_ctx.target_netnsid = ovpn->target_netnsid; peer_ctx.sa_family = ovpn->sa_family; peer_ctx.asymm_id = ovpn->asymm_id; @@ -2109,6 +2323,7 @@ static int ovpn_run_cmd(struct ovpn_ctx *ovpn) struct ovpn_ctx peer_ctx = { 0 }; peer_ctx.ifindex = ovpn->ifindex; + peer_ctx.target_netnsid = ovpn->target_netnsid; peer_ctx.socket = ovpn->socket; peer_ctx.sa_family = AF_UNSPEC; peer_ctx.asymm_id = ovpn->asymm_id; @@ -2181,13 +2396,19 @@ static int ovpn_parse_cmd_args(struct ovpn_ctx *ovpn, int argc, char *argv[]) strscpy(ovpn->ifname, argv[2], IFNAMSIZ - 1); ovpn->ifname[IFNAMSIZ - 1] = '\0'; - /* all commands, except NEW_IFNAME, needs an ifindex */ + /* all commands, except NEW_IFACE, need an ifindex */ if (ovpn->cmd != CMD_NEW_IFACE) { - ovpn->ifindex = if_nametoindex(ovpn->ifname); - if (!ovpn->ifindex) { - fprintf(stderr, "cannot find interface: %s\n", - strerror(errno)); - return -1; + if (ovpn->target_netns_name) { + ret = ovpn_resolve_netns(ovpn); + if (ret < 0) + return ret; + } else { + ovpn->ifindex = if_nametoindex(ovpn->ifname); + if (!ovpn->ifindex) { + fprintf(stderr, "cannot find interface: %s\n", + strerror(errno)); + return -1; + } } } @@ -2433,30 +2654,52 @@ static int ovpn_parse_cmd_args(struct ovpn_ctx *ovpn, int argc, char *argv[]) int main(int argc, char *argv[]) { + const char *program = argv[0]; struct ovpn_ctx ovpn; int ret; + memset(&ovpn, 0, sizeof(ovpn)); + if (argc > 1 && !strcmp(argv[1], "-n")) { + if (argc < 4) { + fprintf(stderr, + "Error: -n requires a namespace and a command.\n\n"); + usage(program); + return -EINVAL; + } + + ovpn.target_netns_name = argv[2]; + argc -= 2; + argv += 2; + } + if (argc < 2) { - usage(argv[0]); + usage(program); return -1; } - memset(&ovpn, 0, sizeof(ovpn)); + ovpn.target_netnsid = NETNSA_NSID_NOT_ASSIGNED; ovpn.sa_family = AF_UNSPEC; ovpn.cipher = OVPN_CIPHER_ALG_NONE; ovpn.cmd = ovpn_parse_cmd(argv[1]); if (ovpn.cmd == CMD_INVALID) { fprintf(stderr, "Error: unknown command.\n\n"); - usage(argv[0]); + usage(program); return -1; } + if (ovpn.target_netns_name && + !ovpn_cmd_supports_target_netns(ovpn.cmd)) { + fprintf(stderr, "Error: -n is not supported for command %s.\n", + argv[1]); + return -EOPNOTSUPP; + } + ret = ovpn_parse_cmd_args(&ovpn, argc, argv); if (ret < 0) { fprintf(stderr, "Error: invalid arguments.\n\n"); if (ret == -EINVAL) - usage(argv[0]); + usage(program); return ret; } diff --git a/tools/testing/selftests/net/ovpn/test-close-socket.sh b/tools/testing/selftests/net/ovpn/test-close-socket.sh index ec9a51bbf3c92..0e4e33b2973fd 100755 --- a/tools/testing/selftests/net/ovpn/test-close-socket.sh +++ b/tools/testing/selftests/net/ovpn/test-close-socket.sh @@ -40,10 +40,10 @@ ovpn_prepare_network() { for p in $(seq 1 ${OVPN_NUM_PEERS}); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "set peer0 timeout for peer ${p}" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \ + "${OVPN_CLI}" -n ovpn_peer0 set_peer tun0 \ ${p} 60 120 ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ + "${OVPN_CLI}" -n "${peer_ns}" set_peer \ tun${p} $((p + OVPN_ID_OFFSET)) 60 120 done } diff --git a/tools/testing/selftests/net/ovpn/test-mark.sh b/tools/testing/selftests/net/ovpn/test-mark.sh index 7c1d56e9c525d..8a9ca52f86be1 100755 --- a/tools/testing/selftests/net/ovpn/test-mark.sh +++ b/tools/testing/selftests/net/ovpn/test-mark.sh @@ -42,7 +42,7 @@ ovpn_mark_prepare_network() { ASYMM "${OVPN_UDP_PEERS_FILE}" "${MARK}" for p in $(seq 1 3); do ovpn_cmd_ok "install server key for peer ${p}" \ - ip netns exec ovpn_peer0 "${OVPN_CLI}" new_key tun0 \ + "${OVPN_CLI}" -n ovpn_peer0 new_key tun0 \ "${p}" 1 0 "${OVPN_ALG}" 0 data64.key done @@ -53,10 +53,10 @@ ovpn_mark_prepare_network() { for p in $(seq 1 3); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "set peer0 timeout for peer ${p}" \ - ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \ + "${OVPN_CLI}" -n ovpn_peer0 set_peer tun0 \ "${p}" 60 120 ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \ - ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \ + "${OVPN_CLI}" -n "${peer_ns}" set_peer \ tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120 done } diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh index 9b5610837032f..468dd7985c8f2 100755 --- a/tools/testing/selftests/net/ovpn/test.sh +++ b/tools/testing/selftests/net/ovpn/test.sh @@ -48,10 +48,10 @@ ovpn_prepare_network() { for p in $(seq 1 ${OVPN_NUM_PEERS}); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "set peer0 timeout for peer ${p}" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \ + "${OVPN_CLI}" -n ovpn_peer0 set_peer tun0 \ ${p} 60 120 ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ + "${OVPN_CLI}" -n "${peer_ns}" set_peer \ tun${p} $((p + OVPN_ID_OFFSET)) 60 120 done } @@ -151,14 +151,14 @@ ovpn_run_key_rollover() { for p in $(seq 1 ${OVPN_NUM_PEERS}); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "add secondary key on peer0 for peer ${p}" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} new_key tun0 \ + "${OVPN_CLI}" -n ovpn_peer0 new_key tun0 \ ${p} 2 1 ${OVPN_ALG} 0 data64.key ovpn_cmd_ok "add secondary key on peer${p} for peer ${p}" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${p} \ + "${OVPN_CLI}" -n "${peer_ns}" new_key tun${p} \ $((p + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 \ data64.key ovpn_cmd_ok "swap keys on peer${p}" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} swap_keys \ + "${OVPN_CLI}" -n "${peer_ns}" swap_keys \ tun${p} $((p + OVPN_ID_OFFSET)) done } @@ -166,22 +166,22 @@ ovpn_run_key_rollover() { ovpn_run_queries() { ovpn_log "Querying all peers:" - ovpn_cmd_ok "query all peers from peer0" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 - ovpn_cmd_ok "query all peers from peer1" \ - ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1 + ovpn_cmd_ok "query all peers on peer0" \ + "${OVPN_CLI}" -n ovpn_peer0 get_peer tun0 + ovpn_cmd_ok "query all peers on peer1" \ + "${OVPN_CLI}" -n ovpn_peer1 get_peer tun1 ovpn_log "Querying peer 1:" - ovpn_cmd_ok "query peer 1 from peer0" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 1 + ovpn_cmd_ok "query peer 1 on peer0" \ + "${OVPN_CLI}" -n ovpn_peer0 get_peer tun0 1 } ovpn_query_peer_missing() { ovpn_log "Querying non-existent peer 20:" ovpn_cmd_fail "query missing peer 20 on peer0" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 20 + "${OVPN_CLI}" -n ovpn_peer0 get_peer tun0 20 } ovpn_run_peer_cleanup() { @@ -191,9 +191,9 @@ ovpn_run_peer_cleanup() { ovpn_log "Deleting peer 1:" ovpn_cmd_ok "delete peer1 on peer0" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 1 + "${OVPN_CLI}" -n ovpn_peer0 del_peer tun0 1 ovpn_cmd_ok "delete peer1 on peer1" \ - ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 \ + "${OVPN_CLI}" -n ovpn_peer1 del_peer tun1 \ $((1 + OVPN_ID_OFFSET)) ovpn_log "Querying keys:" @@ -201,10 +201,10 @@ ovpn_run_peer_cleanup() { for p in $(seq 2 ${OVPN_NUM_PEERS}); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "query peer${p} key 1" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \ + "${OVPN_CLI}" -n "${peer_ns}" get_key tun${p} \ $((p + OVPN_ID_OFFSET)) 1 ovpn_cmd_ok "query peer${p} key 2" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \ + "${OVPN_CLI}" -n "${peer_ns}" get_key tun${p} \ $((p + OVPN_ID_OFFSET)) 2 done } @@ -217,16 +217,16 @@ ovpn_run_traffic_delete_peer() { ovpn_run_bg ping_pid ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1 sleep 2 ovpn_cmd_ok "delete peer0 peer 2" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 2 + "${OVPN_CLI}" -n ovpn_peer0 del_peer tun0 2 if [ "${OVPN_PROTO}" == "TCP" ]; then # In TCP mode this command is expected to fail for both peers. ovpn_cmd_mayfail "delete peer2 peer 2 (TCP non-fatal)" \ - ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 \ + "${OVPN_CLI}" -n ovpn_peer2 del_peer tun2 \ $((2 + OVPN_ID_OFFSET)) else - ovpn_cmd_ok "delete peer2 peer 2" ip netns exec ovpn_peer2 \ - ${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET)) + ovpn_cmd_ok "delete peer2 peer 2" "${OVPN_CLI}" -n ovpn_peer2 \ + del_peer tun2 $((2 + OVPN_ID_OFFSET)) fi wait "${ping_pid}" || true @@ -241,10 +241,10 @@ ovpn_run_key_cleanup() { for p in $(seq 3 ${OVPN_NUM_PEERS}); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "delete key 1 for peer${p}" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \ + "${OVPN_CLI}" -n "${peer_ns}" del_key tun${p} \ $((p + OVPN_ID_OFFSET)) 1 ovpn_cmd_ok "delete key 2 for peer${p}" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \ + "${OVPN_CLI}" -n "${peer_ns}" del_key tun${p} \ $((p + OVPN_ID_OFFSET)) 2 done } @@ -258,11 +258,11 @@ ovpn_run_timeouts() { for p in $(seq 3 ${OVPN_NUM_PEERS}); do # Non-fatal: this may fail in some protocol modes. ovpn_cmd_mayfail "set peer0 timeout for peer ${p} (non-fatal)" \ - ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \ + "${OVPN_CLI}" -n ovpn_peer0 set_peer tun0 \ ${p} 3 3 peer_ns="ovpn_peer${p}" ovpn_cmd_ok "disable timeout on peer${p} while peer0 adjusts \ - state" ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ + state" "${OVPN_CLI}" -n "${peer_ns}" set_peer \ tun${p} $((p + OVPN_ID_OFFSET)) 0 0 done # wait for peers to timeout @@ -273,7 +273,7 @@ ovpn_run_timeouts() { for p in $(seq 3 ${OVPN_NUM_PEERS}); do peer_ns="ovpn_peer${p}" ovpn_cmd_ok "set peer${p} P2P timeout" \ - ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \ + "${OVPN_CLI}" -n "${peer_ns}" set_peer \ tun${p} $((p + OVPN_ID_OFFSET)) 3 3 done sleep 5