[PATCH 1/1] wireguard: Add support to bind socket(s) to device
Maximilian Wilhelm
max at sdn.clinic
Mon Nov 15 16:04:29 UTC 2021
From: Maximilian Wilhelm <max at sdn.clinic>
This introduces support for binding Wireguards UDP socket(s) to a
given interface allowing to send/receive encapsulated packets via
a VRF.
Signed-off-by: Maximilian Wilhelm <max at sdn.clinic>
---
drivers/net/wireguard/device.h | 1 +
drivers/net/wireguard/netlink.c | 7 ++++++-
drivers/net/wireguard/socket.c | 13 +++++++++++++
include/uapi/linux/wireguard.h | 2 ++
4 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireguard/device.h b/drivers/net/wireguard/device.h
index 854bc3d97150..85f9fe687cb8 100644
--- a/drivers/net/wireguard/device.h
+++ b/drivers/net/wireguard/device.h
@@ -56,6 +56,7 @@ struct wg_device {
struct list_head device_list, peer_list;
unsigned int num_peers, device_update_gen;
u32 fwmark;
+ u32 bind_ifindex;
u16 incoming_port;
};
diff --git a/drivers/net/wireguard/netlink.c
b/drivers/net/wireguard/netlink.c
index d0f3b6d7f408..064402a11eb3 100644
--- a/drivers/net/wireguard/netlink.c
+++ b/drivers/net/wireguard/netlink.c
@@ -27,7 +27,8 @@ static const struct nla_policy
device_policy[WGDEVICE_A_MAX + 1] = {
[WGDEVICE_A_FLAGS] = { .type = NLA_U32 },
[WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 },
[WGDEVICE_A_FWMARK] = { .type = NLA_U32 },
- [WGDEVICE_A_PEERS] = { .type = NLA_NESTED }
+ [WGDEVICE_A_PEERS] = { .type = NLA_NESTED },
+ [WGDEVICE_A_BIND_IFINDEX] = { .type = NLA_U32 }
};
static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
@@ -232,6 +233,7 @@ static int wg_get_device_dump(struct sk_buff *skb,
struct netlink_callback *cb)
if (nla_put_u16(skb, WGDEVICE_A_LISTEN_PORT,
wg->incoming_port) ||
nla_put_u32(skb, WGDEVICE_A_FWMARK, wg->fwmark) ||
+ nla_put_u32(skb, WGDEVICE_A_BIND_IFINDEX, wg->bind_ifindex) ||
nla_put_u32(skb, WGDEVICE_A_IFINDEX, wg->dev->ifindex) ||
nla_put_string(skb, WGDEVICE_A_IFNAME, wg->dev->name))
goto out;
@@ -531,6 +533,9 @@ static int wg_set_device(struct sk_buff *skb, struct
genl_info *info)
wg_socket_clear_peer_endpoint_src(peer);
}
+ if (info->attrs[WGDEVICE_A_BIND_IFINDEX])
+ wg->bind_ifindex = nla_get_u32(info->attrs[WGDEVICE_A_BIND_IFINDEX]);
+
if (info->attrs[WGDEVICE_A_LISTEN_PORT]) {
ret = set_port(wg,
nla_get_u16(info->attrs[WGDEVICE_A_LISTEN_PORT]));
diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c
index 8c496b747108..d319288a8f3b 100644
--- a/drivers/net/wireguard/socket.c
+++ b/drivers/net/wireguard/socket.c
@@ -35,6 +35,9 @@ static int send4(struct wg_device *wg, struct sk_buff
*skb,
skb->dev = wg->dev;
skb->mark = wg->fwmark;
+ if (wg->bind_ifindex)
+ fl.flowi4_oif = wg->bind_ifindex;
+
rcu_read_lock_bh();
sock = rcu_dereference_bh(wg->sock4);
@@ -115,6 +118,9 @@ static int send6(struct wg_device *wg, struct
sk_buff *skb,
skb->dev = wg->dev;
skb->mark = wg->fwmark;
+ if (wg->bind_ifindex)
+ fl.flowi6_oif = wg->bind_ifindex;
+
rcu_read_lock_bh();
sock = rcu_dereference_bh(wg->sock6);
@@ -379,6 +385,13 @@ int wg_socket_init(struct wg_device *wg, u16 port)
if (unlikely(!net))
return -ENONET;
+ if (wg->bind_ifindex) {
+ port4.bind_ifindex = wg->bind_ifindex;
+#if IS_ENABLED(CONFIG_IPV6)
+ port6.bind_ifindex = wg->bind_ifindex;
+#endif
+ }
+
#if IS_ENABLED(CONFIG_IPV6)
retry:
#endif
diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h
index ae88be14c947..5c49919596b8 100644
--- a/include/uapi/linux/wireguard.h
+++ b/include/uapi/linux/wireguard.h
@@ -114,6 +114,7 @@
* 0: NLA_NESTED
* ...
* ...
+ * WGDEVICE_A_BIND_IFINDEX: NLA_U32
*
* It is possible that the amount of configuration data exceeds that of
* the maximum message length accepted by the kernel. In that case,
several
@@ -157,6 +158,7 @@ enum wgdevice_attribute {
WGDEVICE_A_LISTEN_PORT,
WGDEVICE_A_FWMARK,
WGDEVICE_A_PEERS,
+ WGDEVICE_A_BIND_IFINDEX,
__WGDEVICE_A_LAST
};
#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1)
--
2.20.1
More information about the WireGuard
mailing list