From: Maximilian Wilhelm <[email protected]>

  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 <[email protected]>
---
 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

Reply via email to