lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250812125155.3808-3-richardbgobert@gmail.com>
Date: Tue, 12 Aug 2025 14:51:52 +0200
From: Richard Gobert <richardbgobert@...il.com>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net,
	edumazet@...gle.com,
	kuba@...nel.org,
	pabeni@...hat.com,
	horms@...nel.org,
	donald.hunter@...il.com,
	andrew+netdev@...n.ch,
	dsahern@...nel.org,
	shuah@...nel.org,
	daniel@...earbox.net,
	jacob.e.keller@...el.com,
	razor@...ckwall.org,
	idosch@...dia.com,
	petrm@...dia.com,
	menglong8.dong@...il.com,
	martin.lau@...nel.org,
	linux-kernel@...r.kernel.org,
	Richard Gobert <richardbgobert@...il.com>
Subject: [PATCH net-next v5 2/5] net: vxlan: add netlink option to bind vxlan sockets to local addresses

Currently, VXLAN sockets always bind to 0.0.0.0, even when a local
address is defined. This commit adds a netlink option to change
this behavior.

If two VXLAN endpoints are connected through two separate subnets,
they are each able to receive traffic through both subnets, regardless
of the local address. The new option will break this behavior.

Disable the option by default.

Signed-off-by: Richard Gobert <richardbgobert@...il.com>
---
 drivers/net/vxlan/vxlan_core.c     | 43 +++++++++++++++++++++++++++---
 include/net/vxlan.h                |  1 +
 include/uapi/linux/if_link.h       |  1 +
 tools/include/uapi/linux/if_link.h |  1 +
 4 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index f32be2e301f2..15fe9d83c724 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -3406,6 +3406,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
 	[IFLA_VXLAN_LABEL_POLICY]       = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX),
 	[IFLA_VXLAN_RESERVED_BITS] = NLA_POLICY_EXACT_LEN(sizeof(struct vxlanhdr)),
 	[IFLA_VXLAN_MC_ROUTE]		= NLA_POLICY_MAX(NLA_U8, 1),
+	[IFLA_VXLAN_LOCALBIND]	= NLA_POLICY_MAX(NLA_U8, 1),
 };
 
 static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -4044,15 +4045,37 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
 		conf->vni = vni;
 	}
 
+	if (data[IFLA_VXLAN_LOCALBIND]) {
+		if (changelink) {
+			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCALBIND], "Cannot rebind locally");
+			return -EOPNOTSUPP;
+		}
+
+		err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBIND,
+				    VXLAN_F_LOCALBIND, changelink,
+				    false, extack);
+		if (err)
+			return err;
+	}
+
 	if (data[IFLA_VXLAN_GROUP]) {
+		__be32 addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]);
+
 		if (changelink && (conf->remote_ip.sa.sa_family != AF_INET)) {
 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "New group address family does not match old group");
 			return -EOPNOTSUPP;
 		}
 
-		conf->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]);
+		if ((conf->flags & VXLAN_F_LOCALBIND) && ipv4_is_multicast(addr)) {
+			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP], "Cannot add multicast group when bound locally");
+			return -EOPNOTSUPP;
+		}
+
+		conf->remote_ip.sin.sin_addr.s_addr = addr;
 		conf->remote_ip.sa.sa_family = AF_INET;
 	} else if (data[IFLA_VXLAN_GROUP6]) {
+		struct in6_addr addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]);
+
 		if (!IS_ENABLED(CONFIG_IPV6)) {
 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "IPv6 support not enabled in the kernel");
 			return -EPFNOSUPPORT;
@@ -4063,7 +4086,12 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
 			return -EOPNOTSUPP;
 		}
 
-		conf->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]);
+		if ((conf->flags & VXLAN_F_LOCALBIND) && ipv6_addr_is_multicast(&addr)) {
+			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_GROUP6], "Cannot add multicast group when bound locally");
+			return -EOPNOTSUPP;
+		}
+
+		conf->remote_ip.sin6.sin6_addr = addr;
 		conf->remote_ip.sa.sa_family = AF_INET6;
 	}
 
@@ -4071,6 +4099,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
 		if (changelink && (conf->saddr.sa.sa_family != AF_INET)) {
 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "New local address family does not match old");
 			return -EOPNOTSUPP;
+		} else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) {
+			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL], "Cannot change local address when bound locally");
+			return -EOPNOTSUPP;
 		}
 
 		conf->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]);
@@ -4084,6 +4115,9 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
 		if (changelink && (conf->saddr.sa.sa_family != AF_INET6)) {
 			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "New local address family does not match old");
 			return -EOPNOTSUPP;
+		} else if (changelink && (conf->flags & VXLAN_F_LOCALBIND)) {
+			NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_VXLAN_LOCAL6], "Cannot change local address when bound locally");
+			return -EOPNOTSUPP;
 		}
 
 		/* TODO: respect scope id */
@@ -4517,6 +4551,7 @@ static size_t vxlan_get_size(const struct net_device *dev)
 		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VNIFILTER */
 		/* IFLA_VXLAN_RESERVED_BITS */
 		nla_total_size(sizeof(struct vxlanhdr)) +
+		nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBIND */
 		0;
 }
 
@@ -4596,7 +4631,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
 	    nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX,
 		       !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) ||
 	    nla_put_u8(skb, IFLA_VXLAN_LOCALBYPASS,
-		       !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS)))
+		       !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS)) ||
+	    nla_put_u8(skb, IFLA_VXLAN_LOCALBIND,
+		       !!(vxlan->cfg.flags & VXLAN_F_LOCALBIND)))
 		goto nla_put_failure;
 
 	if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 0ee50785f4f1..e356b5294535 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -333,6 +333,7 @@ struct vxlan_dev {
 #define VXLAN_F_MDB			0x40000
 #define VXLAN_F_LOCALBYPASS		0x80000
 #define VXLAN_F_MC_ROUTE		0x100000
+#define VXLAN_F_LOCALBIND		0x200000
 
 /* Flags that are used in the receive path. These flags must match in
  * order for a socket to be shareable
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 784ace3a519c..7350129b1444 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1399,6 +1399,7 @@ enum {
 	IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */
 	IFLA_VXLAN_RESERVED_BITS,
 	IFLA_VXLAN_MC_ROUTE,
+	IFLA_VXLAN_LOCALBIND,
 	__IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX	(__IFLA_VXLAN_MAX - 1)
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
index 7e46ca4cd31b..eee934cc2cf4 100644
--- a/tools/include/uapi/linux/if_link.h
+++ b/tools/include/uapi/linux/if_link.h
@@ -1396,6 +1396,7 @@ enum {
 	IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */
 	IFLA_VXLAN_LOCALBYPASS,
 	IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */
+	IFLA_VXLAN_LOCALBIND,
 	__IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX	(__IFLA_VXLAN_MAX - 1)
-- 
2.36.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ