* [PATCH v3 01/12] device: protect socket_init with device_update_lock
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 02/12] netlink: check for CAP_NET_ADMIN manually Julian Orth
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
`set_port` in netlink.c races with `open` in device.c. This can cause
the following code flow:
* thread 1: set_port: device is not up
* thread 2: device is opened
* thread 2: open: called and calls socket_init with the original port
* thread 1: set_port: sets incoming_port to the new port and returns
incoming_port is then inconsistent. While this is not particularly
critical, it will become more critial when ste_port also sets the
transit namespace.
---
src/device.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/device.c b/src/device.c
index 255ad49..88c228b 100644
--- a/src/device.c
+++ b/src/device.c
@@ -53,17 +53,18 @@ static int open(struct net_device *dev)
#endif
#endif
+ mutex_lock(&wg->device_update_lock);
ret = socket_init(wg, wg->incoming_port);
if (ret < 0)
- return ret;
- mutex_lock(&wg->device_update_lock);
+ goto out;
list_for_each_entry (peer, &wg->peer_list, peer_list) {
packet_send_staged_packets(peer);
if (peer->persistent_keepalive_interval)
packet_send_keepalive(peer);
}
+out:
mutex_unlock(&wg->device_update_lock);
- return 0;
+ return ret;
}
#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_ANDROID)
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 02/12] netlink: check for CAP_NET_ADMIN manually
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
2018-09-11 19:13 ` [PATCH v3 01/12] device: protect socket_init with device_update_lock Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 03/12] netlink: allow specifying the device namespace Julian Orth
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
---
src/netlink.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/netlink.c b/src/netlink.c
index 0bd2b97..a857aff 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -172,9 +172,12 @@ static int get_device_start(struct netlink_callback *cb)
int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + genl_family.hdrsize, attrs,
genl_family.maxattr, device_policy, NULL);
struct wireguard_device *wg;
+ struct net *dev_net = sock_net(cb->skb->sk);
if (ret < 0)
return ret;
+ if (!netlink_ns_capable(cb->skb, dev_net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
cb->args[2] = (long)kzalloc(sizeof(struct allowedips_cursor),
GFP_KERNEL);
if (unlikely(!cb->args[2]))
@@ -477,7 +480,15 @@ out:
static int set_device(struct sk_buff *skb, struct genl_info *info)
{
int ret;
- struct wireguard_device *wg = lookup_interface(info->attrs, skb);
+ struct wireguard_device *wg;
+ struct net *dev_net = sock_net(skb->sk);
+
+ if (!netlink_ns_capable(skb, dev_net->user_ns, CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto out_nodev;
+ }
+
+ wg = lookup_interface(info->attrs, skb);
if (IS_ERR(wg)) {
ret = PTR_ERR(wg);
@@ -580,12 +591,10 @@ struct genl_ops genl_ops[] = {
.dumpit = get_device_dump,
.done = get_device_done,
.policy = device_policy,
- .flags = GENL_UNS_ADMIN_PERM
}, {
.cmd = WG_CMD_SET_DEVICE,
.doit = set_device,
.policy = device_policy,
- .flags = GENL_UNS_ADMIN_PERM
}
};
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 03/12] netlink: allow specifying the device namespace
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
2018-09-11 19:13 ` [PATCH v3 01/12] device: protect socket_init with device_update_lock Julian Orth
2018-09-11 19:13 ` [PATCH v3 02/12] netlink: check for CAP_NET_ADMIN manually Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 04/12] netlink: restrict access to the UDP socket Julian Orth
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
This commit adds two new attributes of which at most one may be
provided:
* WGDEVICE_A_DEV_NETNS_PID: NLA_U32
* WGDEVICE_A_DEV_NETNS_FD: NLA_U32
The Wireguard device is then looked up in this namespace instead of the
namespace of the netlink socket.
---
src/netlink.c | 82 ++++++++++++++++++++++++++++++++++----------
src/uapi/wireguard.h | 26 ++++++++++++--
2 files changed, 87 insertions(+), 21 deletions(-)
diff --git a/src/netlink.c b/src/netlink.c
index a857aff..19fe92d 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -24,7 +24,9 @@ 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_DEV_NETNS_PID] = { .type = NLA_U32 },
+ [WGDEVICE_A_DEV_NETNS_FD] = { .type = NLA_U32 },
};
static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
@@ -47,17 +49,17 @@ static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = {
};
static struct wireguard_device *lookup_interface(struct nlattr **attrs,
- struct sk_buff *skb)
+ struct net *net)
{
struct net_device *dev = NULL;
if (!attrs[WGDEVICE_A_IFINDEX] == !attrs[WGDEVICE_A_IFNAME])
return ERR_PTR(-EBADR);
if (attrs[WGDEVICE_A_IFINDEX])
- dev = dev_get_by_index(sock_net(skb->sk),
+ dev = dev_get_by_index(net,
nla_get_u32(attrs[WGDEVICE_A_IFINDEX]));
else if (attrs[WGDEVICE_A_IFNAME])
- dev = dev_get_by_name(sock_net(skb->sk),
+ dev = dev_get_by_name(net,
nla_data(attrs[WGDEVICE_A_IFNAME]));
if (!dev)
return ERR_PTR(-ENODEV);
@@ -166,30 +168,64 @@ err:
return -EMSGSIZE;
}
+static struct net *get_attr_net(struct nlattr *net_pid, struct nlattr *net_fd)
+{
+ if (net_pid && net_fd)
+ return ERR_PTR(-EINVAL);
+ if (net_pid)
+ return get_net_ns_by_pid(nla_get_u32(net_pid));
+ if (net_fd)
+ return get_net_ns_by_fd(nla_get_u32(net_fd));
+ return NULL;
+}
+
static int get_device_start(struct netlink_callback *cb)
{
struct nlattr **attrs = genl_family_attrbuf(&genl_family);
int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + genl_family.hdrsize, attrs,
genl_family.maxattr, device_policy, NULL);
struct wireguard_device *wg;
- struct net *dev_net = sock_net(cb->skb->sk);
+ struct net *owned_dev_net = NULL, *dev_net;
+ struct allowedips_cursor *cursor = NULL;
if (ret < 0)
return ret;
- if (!netlink_ns_capable(cb->skb, dev_net->user_ns, CAP_NET_ADMIN))
- return -EPERM;
- cb->args[2] = (long)kzalloc(sizeof(struct allowedips_cursor),
- GFP_KERNEL);
- if (unlikely(!cb->args[2]))
- return -ENOMEM;
- wg = lookup_interface(attrs, cb->skb);
+
+ owned_dev_net = get_attr_net(attrs[WGDEVICE_A_DEV_NETNS_PID],
+ attrs[WGDEVICE_A_DEV_NETNS_FD]);
+ if (IS_ERR(owned_dev_net)) {
+ ret = PTR_ERR(owned_dev_net);
+ owned_dev_net = NULL;
+ goto out;
+ }
+ dev_net = owned_dev_net ? : sock_net(cb->skb->sk);
+ if (!netlink_ns_capable(cb->skb, dev_net->user_ns, CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
+ if (unlikely(!cursor)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wg = lookup_interface(attrs, dev_net);
if (IS_ERR(wg)) {
- kfree((void *)cb->args[2]);
- cb->args[2] = 0;
- return PTR_ERR(wg);
+ ret = PTR_ERR(wg);
+ goto out;
}
+
cb->args[0] = (long)wg;
- return 0;
+ cb->args[2] = (long)cursor;
+ cursor = NULL;
+
+out:
+ if (cursor)
+ kfree(cursor);
+ if (owned_dev_net)
+ put_net(owned_dev_net);
+ return ret;
}
static int get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@ -481,14 +517,21 @@ static int set_device(struct sk_buff *skb, struct genl_info *info)
{
int ret;
struct wireguard_device *wg;
- struct net *dev_net = sock_net(skb->sk);
+ struct net *owned_dev_net, *dev_net;
+ owned_dev_net = get_attr_net(info->attrs[WGDEVICE_A_DEV_NETNS_PID],
+ info->attrs[WGDEVICE_A_DEV_NETNS_FD]);
+ if (IS_ERR(owned_dev_net)) {
+ ret = PTR_ERR(wg);
+ goto out_nonet;
+ }
+ dev_net = owned_dev_net ? : sock_net(skb->sk);
if (!netlink_ns_capable(skb, dev_net->user_ns, CAP_NET_ADMIN)) {
ret = -EPERM;
goto out_nodev;
}
- wg = lookup_interface(info->attrs, skb);
+ wg = lookup_interface(info->attrs, dev_net);
if (IS_ERR(wg)) {
ret = PTR_ERR(wg);
@@ -571,6 +614,9 @@ out:
rtnl_unlock();
dev_put(wg->dev);
out_nodev:
+ if (owned_dev_net)
+ put_net(owned_dev_net);
+out_nonet:
if (info->attrs[WGDEVICE_A_PRIVATE_KEY])
memzero_explicit(nla_data(info->attrs[WGDEVICE_A_PRIVATE_KEY]),
nla_len(info->attrs[WGDEVICE_A_PRIVATE_KEY]));
diff --git a/src/uapi/wireguard.h b/src/uapi/wireguard.h
index 3d73ad7..cff46f9 100644
--- a/src/uapi/wireguard.h
+++ b/src/uapi/wireguard.h
@@ -20,6 +20,16 @@
* WGDEVICE_A_IFINDEX: NLA_U32
* WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
*
+ * At most one of the following may be provided:
+ *
+ * WGDEVICE_A_DEV_NETNS_PID: NLA_U32
+ * WGDEVICE_A_DEV_NETNS_FD: NLA_U32
+ *
+ * If they are provided, the Wireguard device will be looked up in this network
+ * namespace. Otherwise it is looked up in the network namespace of the netlink
+ * socket. The caller must have CAP_NET_ADMIN in the namespace of the Wireguard
+ * device.
+ *
* The kernel will then return several messages (NLM_F_MULTI) containing the
* following tree of nested items:
*
@@ -72,9 +82,15 @@
* WG_CMD_SET_DEVICE
* -----------------
*
- * May only be called via NLM_F_REQUEST. The command should contain the
- * following tree of nested items, containing one but not both of
- * WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME:
+ * May only be called via NLM_F_REQUEST. The command must contain the following
+ * tree of nested items. Exactly one of WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME
+ * must be provided. All other top-level items are optional. At most one of
+ * WGDEVICE_A_DEV_NETNS_PID and WGDEVICE_A_DEV_NETNS_FD may be provided.
+ *
+ * If WGDEVICE_A_DEV_NETNS_PID/FD is provided, the Wireguard device is looked up
+ * in this network namespace. Otherwise it is looked up in the network namespace
+ * of the netlink socket. The caller must have CAP_NET_ADMIN in the namespace of
+ * the Wireguard device.
*
* WGDEVICE_A_IFINDEX: NLA_U32
* WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
@@ -82,6 +98,8 @@
* peers should be removed prior to adding the list below.
* WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove
* WGDEVICE_A_LISTEN_PORT: NLA_U16, 0 to choose randomly
+ * WGDEVICE_A_DEV_NETNS_PID: NLA_U32
+ * WGDEVICE_A_DEV_NETNS_FD: NLA_U32
* WGDEVICE_A_FWMARK: NLA_U32, 0 to disable
* WGDEVICE_A_PEERS: NLA_NESTED
* 0: NLA_NESTED
@@ -154,6 +172,8 @@ enum wgdevice_attribute {
WGDEVICE_A_LISTEN_PORT,
WGDEVICE_A_FWMARK,
WGDEVICE_A_PEERS,
+ WGDEVICE_A_DEV_NETNS_PID,
+ WGDEVICE_A_DEV_NETNS_FD,
__WGDEVICE_A_LAST
};
#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1)
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 04/12] netlink: restrict access to the UDP socket
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (2 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 03/12] netlink: allow specifying the device namespace Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 05/12] device: rename creating_net to transit_net Julian Orth
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
To interact with the UDP socket the caller must either be in the
network namespace of the socket or have CAP_NET_ADMIN in that network
namespace.
---
src/netlink.c | 21 ++++++++++++++++++---
src/uapi/wireguard.h | 7 +++++++
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/src/netlink.c b/src/netlink.c
index 19fe92d..0775a2a 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -179,6 +179,14 @@ static struct net *get_attr_net(struct nlattr *net_pid, struct nlattr *net_fd)
return NULL;
}
+static int test_socket_net_capable(struct net *net)
+{
+ if (net != current->nsproxy->net_ns &&
+ !ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
static int get_device_start(struct netlink_callback *cb)
{
struct nlattr **attrs = genl_family_attrbuf(&genl_family);
@@ -255,9 +263,12 @@ static int get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
genl_dump_check_consistent(cb, hdr);
if (!last_peer_cursor) {
- if (nla_put_u16(skb, WGDEVICE_A_LISTEN_PORT,
- wg->incoming_port) ||
- nla_put_u32(skb, WGDEVICE_A_FWMARK, wg->fwmark) ||
+ if (test_socket_net_capable(wg->creating_net) == 0) {
+ if (nla_put_u16(skb, WGDEVICE_A_LISTEN_PORT,
+ wg->incoming_port))
+ goto out;
+ }
+ if (nla_put_u32(skb, WGDEVICE_A_FWMARK, wg->fwmark) ||
nla_put_u32(skb, WGDEVICE_A_IFINDEX, wg->dev->ifindex) ||
nla_put_string(skb, WGDEVICE_A_IFNAME, wg->dev->name))
goto out;
@@ -344,7 +355,11 @@ static int get_device_done(struct netlink_callback *cb)
static int set_port(struct wireguard_device *wg, u16 port)
{
struct wireguard_peer *peer;
+ int ret;
+ ret = test_socket_net_capable(wg->creating_net);
+ if (ret)
+ return ret;
if (wg->incoming_port == port)
return 0;
list_for_each_entry (peer, &wg->peer_list, peer_list)
diff --git a/src/uapi/wireguard.h b/src/uapi/wireguard.h
index cff46f9..71958ff 100644
--- a/src/uapi/wireguard.h
+++ b/src/uapi/wireguard.h
@@ -30,6 +30,9 @@
* socket. The caller must have CAP_NET_ADMIN in the namespace of the Wireguard
* device.
*
+ * If the caller is not in the transit namespace and does not have CAP_NET_ADMIN
+ * in the transit namespace, then the WGDEVICE_A_LISTEN_PORT is not returned.
+ *
* The kernel will then return several messages (NLM_F_MULTI) containing the
* following tree of nested items:
*
@@ -92,6 +95,10 @@
* of the netlink socket. The caller must have CAP_NET_ADMIN in the namespace of
* the Wireguard device.
*
+ * If WGDEVICE_A_LISTEN_PORT is provided and the calling process is not in the
+ * transit namespace, then the calling process must have CAP_NET_ADMIN the
+ * transit namespace.
+ *
* WGDEVICE_A_IFINDEX: NLA_U32
* WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
* WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 05/12] device: rename creating_net to transit_net
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (3 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 04/12] netlink: restrict access to the UDP socket Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 06/12] device: store a copy of the device net Julian Orth
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
---
src/device.c | 20 ++++++++++----------
src/device.h | 4 ++--
src/netlink.c | 4 ++--
src/socket.c | 8 ++++----
4 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/src/device.c b/src/device.c
index 88c228b..92aefc4 100644
--- a/src/device.c
+++ b/src/device.c
@@ -243,8 +243,8 @@ static void destruct(struct net_device *dev)
skb_queue_purge(&wg->incoming_handshakes);
free_percpu(dev->tstats);
free_percpu(wg->incoming_handshakes_worker);
- if (wg->have_creating_net_ref)
- put_net(wg->creating_net);
+ if (wg->have_transit_net_ref)
+ put_net(wg->transit_net);
mutex_unlock(&wg->device_update_lock);
pr_debug("%s: Interface deleted\n", dev->name);
@@ -296,7 +296,7 @@ static int newlink(struct net *src_net, struct net_device *dev,
int ret = -ENOMEM;
struct wireguard_device *wg = netdev_priv(dev);
- wg->creating_net = src_net;
+ wg->transit_net = src_net;
init_rwsem(&wg->static_identity.lock);
mutex_init(&wg->socket_update_lock);
mutex_init(&wg->device_update_lock);
@@ -396,13 +396,13 @@ static int netdevice_notification(struct notifier_block *nb,
if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops)
return 0;
- if (dev_net(dev) == wg->creating_net && wg->have_creating_net_ref) {
- put_net(wg->creating_net);
- wg->have_creating_net_ref = false;
- } else if (dev_net(dev) != wg->creating_net &&
- !wg->have_creating_net_ref) {
- wg->have_creating_net_ref = true;
- get_net(wg->creating_net);
+ if (dev_net(dev) == wg->transit_net && wg->have_transit_net_ref) {
+ put_net(wg->transit_net);
+ wg->have_transit_net_ref = false;
+ } else if (dev_net(dev) != wg->transit_net &&
+ !wg->have_transit_net_ref) {
+ wg->have_transit_net_ref = true;
+ get_net(wg->transit_net);
}
return 0;
}
diff --git a/src/device.h b/src/device.h
index 2499782..4b7552c 100644
--- a/src/device.h
+++ b/src/device.h
@@ -40,7 +40,7 @@ struct wireguard_device {
struct net_device *dev;
struct crypt_queue encrypt_queue, decrypt_queue;
struct sock __rcu *sock4, *sock6;
- struct net *creating_net;
+ struct net *transit_net;
struct noise_static_identity static_identity;
struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
struct workqueue_struct *packet_crypt_wq;
@@ -56,7 +56,7 @@ struct wireguard_device {
unsigned int num_peers, device_update_gen;
u32 fwmark;
u16 incoming_port;
- bool have_creating_net_ref;
+ bool have_transit_net_ref;
};
int device_init(void);
diff --git a/src/netlink.c b/src/netlink.c
index 0775a2a..6b4350f 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -263,7 +263,7 @@ static int get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
genl_dump_check_consistent(cb, hdr);
if (!last_peer_cursor) {
- if (test_socket_net_capable(wg->creating_net) == 0) {
+ if (test_socket_net_capable(wg->transit_net) == 0) {
if (nla_put_u16(skb, WGDEVICE_A_LISTEN_PORT,
wg->incoming_port))
goto out;
@@ -357,7 +357,7 @@ static int set_port(struct wireguard_device *wg, u16 port)
struct wireguard_peer *peer;
int ret;
- ret = test_socket_net_capable(wg->creating_net);
+ ret = test_socket_net_capable(wg->transit_net);
if (ret)
return ret;
if (wg->incoming_port == port)
diff --git a/src/socket.c b/src/socket.c
index 2e9e44f..72f3e6a 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -384,18 +384,18 @@ int socket_init(struct wireguard_device *wg, u16 port)
retry:
#endif
- ret = udp_sock_create(wg->creating_net, &port4, &new4);
+ ret = udp_sock_create(wg->transit_net, &port4, &new4);
if (ret < 0) {
pr_err("%s: Could not create IPv4 socket\n", wg->dev->name);
return ret;
}
set_sock_opts(new4);
- setup_udp_tunnel_sock(wg->creating_net, new4, &cfg);
+ setup_udp_tunnel_sock(wg->transit_net, new4, &cfg);
#if IS_ENABLED(CONFIG_IPV6)
if (ipv6_mod_enabled()) {
port6.local_udp_port = inet_sk(new4->sk)->inet_sport;
- ret = udp_sock_create(wg->creating_net, &port6, &new6);
+ ret = udp_sock_create(wg->transit_net, &port6, &new6);
if (ret < 0) {
udp_tunnel_sock_release(new4);
if (ret == -EADDRINUSE && !port && retries++ < 100)
@@ -405,7 +405,7 @@ retry:
return ret;
}
set_sock_opts(new6);
- setup_udp_tunnel_sock(wg->creating_net, new6, &cfg);
+ setup_udp_tunnel_sock(wg->transit_net, new6, &cfg);
}
#endif
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 06/12] device: store a copy of the device net
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (4 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 05/12] device: rename creating_net to transit_net Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 07/12] socket: allow modification of transit_net Julian Orth
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
This eliminates the need for have_transit_net_ref because
have_transit_net_ref == true if and only if dev_net != transit_net.
---
src/device.c | 27 +++++++++++++++++----------
src/device.h | 4 +++-
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/src/device.c b/src/device.c
index 92aefc4..71c0662 100644
--- a/src/device.c
+++ b/src/device.c
@@ -243,7 +243,7 @@ static void destruct(struct net_device *dev)
skb_queue_purge(&wg->incoming_handshakes);
free_percpu(dev->tstats);
free_percpu(wg->incoming_handshakes_worker);
- if (wg->have_transit_net_ref)
+ if (wg->transit_net != wg->dev_net)
put_net(wg->transit_net);
mutex_unlock(&wg->device_update_lock);
@@ -296,7 +296,9 @@ static int newlink(struct net *src_net, struct net_device *dev,
int ret = -ENOMEM;
struct wireguard_device *wg = netdev_priv(dev);
- wg->transit_net = src_net;
+ wg->dev_net = NULL;
+ wg->transit_net = NULL;
+ device_set_nets(wg, dev_net(dev), src_net);
init_rwsem(&wg->static_identity.lock);
mutex_init(&wg->socket_update_lock);
mutex_init(&wg->device_update_lock);
@@ -396,14 +398,8 @@ static int netdevice_notification(struct notifier_block *nb,
if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops)
return 0;
- if (dev_net(dev) == wg->transit_net && wg->have_transit_net_ref) {
- put_net(wg->transit_net);
- wg->have_transit_net_ref = false;
- } else if (dev_net(dev) != wg->transit_net &&
- !wg->have_transit_net_ref) {
- wg->have_transit_net_ref = true;
- get_net(wg->transit_net);
- }
+ device_set_nets(wg, dev_net(dev), wg->transit_net);
+
return 0;
}
@@ -449,3 +445,14 @@ void device_uninit(void)
#endif
rcu_barrier_bh();
}
+
+void device_set_nets(struct wireguard_device *wg, struct net *dev_net,
+ struct net *transit_net)
+{
+ if (wg->transit_net != wg->dev_net)
+ put_net(wg->transit_net);
+ wg->dev_net = dev_net;
+ wg->transit_net = transit_net;
+ if (wg->transit_net != wg->dev_net)
+ get_net(wg->transit_net);
+}
diff --git a/src/device.h b/src/device.h
index 4b7552c..eb229df 100644
--- a/src/device.h
+++ b/src/device.h
@@ -41,6 +41,7 @@ struct wireguard_device {
struct crypt_queue encrypt_queue, decrypt_queue;
struct sock __rcu *sock4, *sock6;
struct net *transit_net;
+ struct net *dev_net;
struct noise_static_identity static_identity;
struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
struct workqueue_struct *packet_crypt_wq;
@@ -56,10 +57,11 @@ struct wireguard_device {
unsigned int num_peers, device_update_gen;
u32 fwmark;
u16 incoming_port;
- bool have_transit_net_ref;
};
int device_init(void);
void device_uninit(void);
+void device_set_nets(struct wireguard_device *wg, struct net *dev_net,
+ struct net *transit_net);
#endif /* _WG_DEVICE_H */
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 07/12] socket: allow modification of transit_net
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (5 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 06/12] device: store a copy of the device net Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 08/12] netlink: allow modification of transit net Julian Orth
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
---
src/device.c | 8 +++++---
src/netlink.c | 2 +-
src/socket.c | 18 ++++++++++--------
src/socket.h | 6 +++---
4 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/src/device.c b/src/device.c
index 71c0662..2b7286b 100644
--- a/src/device.c
+++ b/src/device.c
@@ -54,7 +54,7 @@ static int open(struct net_device *dev)
#endif
mutex_lock(&wg->device_update_lock);
- ret = socket_init(wg, wg->incoming_port);
+ ret = socket_init(wg, wg->transit_net, wg->incoming_port);
if (ret < 0)
goto out;
list_for_each_entry (peer, &wg->peer_list, peer_list) {
@@ -112,7 +112,7 @@ static int stop(struct net_device *dev)
}
mutex_unlock(&wg->device_update_lock);
skb_queue_purge(&wg->incoming_handshakes);
- socket_reinit(wg, NULL, NULL);
+ socket_reinit(wg, NULL, NULL, NULL);
return 0;
}
@@ -228,7 +228,7 @@ static void destruct(struct net_device *dev)
rtnl_unlock();
mutex_lock(&wg->device_update_lock);
wg->incoming_port = 0;
- socket_reinit(wg, NULL, NULL);
+ socket_reinit(wg, NULL, NULL, NULL);
allowedips_free(&wg->peer_allowedips, &wg->device_update_lock);
/* The final references are cleared in the below calls to destroy_workqueue. */
peer_remove_all(wg);
@@ -398,7 +398,9 @@ static int netdevice_notification(struct notifier_block *nb,
if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops)
return 0;
+ mutex_lock(&wg->device_update_lock);
device_set_nets(wg, dev_net(dev), wg->transit_net);
+ mutex_unlock(&wg->device_update_lock);
return 0;
}
diff --git a/src/netlink.c b/src/netlink.c
index 6b4350f..ed16980 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -368,7 +368,7 @@ static int set_port(struct wireguard_device *wg, u16 port)
wg->incoming_port = port;
return 0;
}
- return socket_init(wg, port);
+ return socket_init(wg, wg->transit_net, port);
}
static int set_allowedip(struct wireguard_peer *peer, struct nlattr **attrs)
diff --git a/src/socket.c b/src/socket.c
index 72f3e6a..73dadcd 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -354,7 +354,7 @@ static inline void set_sock_opts(struct socket *sock)
sk_set_memalloc(sock->sk);
}
-int socket_init(struct wireguard_device *wg, u16 port)
+int socket_init(struct wireguard_device *wg, struct net *net, u16 port)
{
int ret;
struct udp_tunnel_sock_cfg cfg = {
@@ -384,18 +384,18 @@ int socket_init(struct wireguard_device *wg, u16 port)
retry:
#endif
- ret = udp_sock_create(wg->transit_net, &port4, &new4);
+ ret = udp_sock_create(net, &port4, &new4);
if (ret < 0) {
pr_err("%s: Could not create IPv4 socket\n", wg->dev->name);
return ret;
}
set_sock_opts(new4);
- setup_udp_tunnel_sock(wg->transit_net, new4, &cfg);
+ setup_udp_tunnel_sock(net, new4, &cfg);
#if IS_ENABLED(CONFIG_IPV6)
if (ipv6_mod_enabled()) {
port6.local_udp_port = inet_sk(new4->sk)->inet_sport;
- ret = udp_sock_create(wg->transit_net, &port6, &new6);
+ ret = udp_sock_create(net, &port6, &new6);
if (ret < 0) {
udp_tunnel_sock_release(new4);
if (ret == -EADDRINUSE && !port && retries++ < 100)
@@ -405,16 +405,16 @@ retry:
return ret;
}
set_sock_opts(new6);
- setup_udp_tunnel_sock(wg->transit_net, new6, &cfg);
+ setup_udp_tunnel_sock(net, new6, &cfg);
}
#endif
- socket_reinit(wg, new4 ? new4->sk : NULL, new6 ? new6->sk : NULL);
+ socket_reinit(wg, net, new4 ? new4->sk : NULL, new6 ? new6->sk : NULL);
return 0;
}
-void socket_reinit(struct wireguard_device *wg, struct sock *new4,
- struct sock *new6)
+void socket_reinit(struct wireguard_device *wg, struct net *net,
+ struct sock *new4, struct sock *new6)
{
struct sock *old4, *old6;
@@ -427,6 +427,8 @@ void socket_reinit(struct wireguard_device *wg, struct sock *new4,
rcu_assign_pointer(wg->sock6, new6);
if (new4)
wg->incoming_port = ntohs(inet_sk(new4)->inet_sport);
+ if (net && wg->transit_net != net)
+ device_set_nets(wg, wg->dev_net, net);
mutex_unlock(&wg->socket_update_lock);
synchronize_rcu_bh();
synchronize_net();
diff --git a/src/socket.h b/src/socket.h
index d873ffa..8419ee9 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -11,9 +11,9 @@
#include <linux/if_vlan.h>
#include <linux/if_ether.h>
-int socket_init(struct wireguard_device *wg, u16 port);
-void socket_reinit(struct wireguard_device *wg, struct sock *new4,
- struct sock *new6);
+int socket_init(struct wireguard_device *wg, struct net *net, u16 port);
+void socket_reinit(struct wireguard_device *wg, struct net *net,
+ struct sock *new4, struct sock *new6);
int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *data,
size_t len, u8 ds);
int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb,
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 08/12] netlink: allow modification of transit net
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (6 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 07/12] socket: allow modification of transit_net Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 09/12] tools: add framework for shared options Julian Orth
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
This commit adds two new attributes of which at most one may be
provided:
* WGDEVICE_A_TRANSIT_NETNS_PID: NLA_U32
* WGDEVICE_A_TRANSIT_NETNS_FD: NLA_U32
The transit namespace is then set to this namespace. The caller must
either be in this namespace or have CAP_NET_ADMIN in it.
---
src/netlink.c | 48 +++++++++++++++++++++++++++++++-------------
src/uapi/wireguard.h | 14 +++++++++----
2 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/src/netlink.c b/src/netlink.c
index ed16980..90d02df 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -27,6 +27,8 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
[WGDEVICE_A_PEERS] = { .type = NLA_NESTED },
[WGDEVICE_A_DEV_NETNS_PID] = { .type = NLA_U32 },
[WGDEVICE_A_DEV_NETNS_FD] = { .type = NLA_U32 },
+ [WGDEVICE_A_TRANSIT_NETNS_PID] = { .type = NLA_U32 },
+ [WGDEVICE_A_TRANSIT_NETNS_FD] = { .type = NLA_U32 },
};
static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
@@ -352,23 +354,44 @@ static int get_device_done(struct netlink_callback *cb)
return 0;
}
-static int set_port(struct wireguard_device *wg, u16 port)
+static int set_socket(struct wireguard_device *wg, struct nlattr **attrs)
{
struct wireguard_peer *peer;
- int ret;
+ struct nlattr *port_attr = attrs[WGDEVICE_A_LISTEN_PORT];
+ u16 port;
+ struct net *net = NULL;
+ int ret = 0;
+
+ net = get_attr_net(attrs[WGDEVICE_A_TRANSIT_NETNS_PID],
+ attrs[WGDEVICE_A_TRANSIT_NETNS_FD]);
+ if (IS_ERR(net))
+ return PTR_ERR(net);
+ if (port_attr)
+ port = nla_get_u16(port_attr);
+ else
+ port = wg->incoming_port;
- ret = test_socket_net_capable(wg->transit_net);
+ ret = test_socket_net_capable(net ? : wg->transit_net);
if (ret)
- return ret;
- if (wg->incoming_port == port)
- return 0;
+ goto out;
+
+ if (wg->incoming_port == port && (!net || wg->transit_net == net))
+ goto out;
+
list_for_each_entry (peer, &wg->peer_list, peer_list)
socket_clear_peer_endpoint_src(peer);
if (!netif_running(wg->dev)) {
wg->incoming_port = port;
- return 0;
+ if (net)
+ device_set_nets(wg, wg->dev_net, net);
+ goto out;
}
- return socket_init(wg, wg->transit_net, port);
+ ret = socket_init(wg, net ? : wg->transit_net, port);
+
+out:
+ if (net)
+ put_net(net);
+ return ret;
}
static int set_allowedip(struct wireguard_peer *peer, struct nlattr **attrs)
@@ -565,12 +588,9 @@ static int set_device(struct sk_buff *skb, struct genl_info *info)
socket_clear_peer_endpoint_src(peer);
}
- if (info->attrs[WGDEVICE_A_LISTEN_PORT]) {
- ret = set_port(
- wg, nla_get_u16(info->attrs[WGDEVICE_A_LISTEN_PORT]));
- if (ret)
- goto out;
- }
+ ret = set_socket(wg, info->attrs);
+ if (ret)
+ goto out;
if (info->attrs[WGDEVICE_A_FLAGS] &&
nla_get_u32(info->attrs[WGDEVICE_A_FLAGS]) &
diff --git a/src/uapi/wireguard.h b/src/uapi/wireguard.h
index 71958ff..35c88d2 100644
--- a/src/uapi/wireguard.h
+++ b/src/uapi/wireguard.h
@@ -88,16 +88,18 @@
* May only be called via NLM_F_REQUEST. The command must contain the following
* tree of nested items. Exactly one of WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME
* must be provided. All other top-level items are optional. At most one of
- * WGDEVICE_A_DEV_NETNS_PID and WGDEVICE_A_DEV_NETNS_FD may be provided.
+ * WGDEVICE_A_TRANSIT_NETNS_PID and WGDEVICE_A_TRANSIT_NETNS_FD may be provided.
+ * At most one of WGDEVICE_A_DEV_NETNS_PID and WGDEVICE_A_DEV_NETNS_FD may be
+ * provided.
*
* If WGDEVICE_A_DEV_NETNS_PID/FD is provided, the Wireguard device is looked up
* in this network namespace. Otherwise it is looked up in the network namespace
* of the netlink socket. The caller must have CAP_NET_ADMIN in the namespace of
* the Wireguard device.
*
- * If WGDEVICE_A_LISTEN_PORT is provided and the calling process is not in the
- * transit namespace, then the calling process must have CAP_NET_ADMIN the
- * transit namespace.
+ * If WGDEVICE_A_TRANSIT_NETNS_PID/FD and/or WGDEVICE_A_LISTEN_PORT are provided
+ * and the calling process is not in the transit namespace, then the calling
+ * process must have CAP_NET_ADMIN the transit namespace.
*
* WGDEVICE_A_IFINDEX: NLA_U32
* WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
@@ -107,6 +109,8 @@
* WGDEVICE_A_LISTEN_PORT: NLA_U16, 0 to choose randomly
* WGDEVICE_A_DEV_NETNS_PID: NLA_U32
* WGDEVICE_A_DEV_NETNS_FD: NLA_U32
+ * WGDEVICE_A_TRANSIT_NETNS_PID: NLA_U32
+ * WGDEVICE_A_TRANSIT_NETNS_FD: NLA_U32
* WGDEVICE_A_FWMARK: NLA_U32, 0 to disable
* WGDEVICE_A_PEERS: NLA_NESTED
* 0: NLA_NESTED
@@ -181,6 +185,8 @@ enum wgdevice_attribute {
WGDEVICE_A_PEERS,
WGDEVICE_A_DEV_NETNS_PID,
WGDEVICE_A_DEV_NETNS_FD,
+ WGDEVICE_A_TRANSIT_NETNS_PID,
+ WGDEVICE_A_TRANSIT_NETNS_FD,
__WGDEVICE_A_LAST
};
#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1)
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 09/12] tools: add framework for shared options
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (7 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 08/12] netlink: allow modification of transit net Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 10/12] tools: allow specifying the device namespace Julian Orth
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
---
src/tools/containers.h | 3 +++
src/tools/genkey.c | 3 ++-
src/tools/pubkey.c | 3 ++-
src/tools/set.c | 3 ++-
src/tools/setconf.c | 3 ++-
src/tools/show.c | 3 ++-
src/tools/showconf.c | 3 ++-
src/tools/subcommands.h | 14 ++++++-----
src/tools/wg.c | 56 +++++++++++++++++++++++++++++++++++------
9 files changed, 72 insertions(+), 19 deletions(-)
diff --git a/src/tools/containers.h b/src/tools/containers.h
index 455d998..8142d65 100644
--- a/src/tools/containers.h
+++ b/src/tools/containers.h
@@ -15,6 +15,9 @@
#include "../uapi/wireguard.h"
+struct wgoptions {
+};
+
struct wgallowedip {
uint16_t family;
union {
diff --git a/src/tools/genkey.c b/src/tools/genkey.c
index d2d4c53..ce45b1a 100644
--- a/src/tools/genkey.c
+++ b/src/tools/genkey.c
@@ -52,11 +52,12 @@ static inline ssize_t get_random_bytes(uint8_t *out, size_t len)
return ret;
}
-int genkey_main(int argc, char *argv[])
+int genkey_main(int argc, char *argv[], struct wgoptions *options)
{
uint8_t key[WG_KEY_LEN];
char base64[WG_KEY_LEN_BASE64];
struct stat stat;
+ (void)options;
if (argc != 1) {
fprintf(stderr, "Usage: %s %s\n", PROG_NAME, argv[0]);
diff --git a/src/tools/pubkey.c b/src/tools/pubkey.c
index 385145b..19e41e3 100644
--- a/src/tools/pubkey.c
+++ b/src/tools/pubkey.c
@@ -11,11 +11,12 @@
#include "encoding.h"
#include "subcommands.h"
-int pubkey_main(int argc, char *argv[])
+int pubkey_main(int argc, char *argv[], struct wgoptions *options)
{
uint8_t key[WG_KEY_LEN];
char base64[WG_KEY_LEN_BASE64];
int trailing_char;
+ (void)options;
if (argc != 1) {
fprintf(stderr, "Usage: %s %s\n", PROG_NAME, argv[0]);
diff --git a/src/tools/set.c b/src/tools/set.c
index d44fed9..2fb782b 100644
--- a/src/tools/set.c
+++ b/src/tools/set.c
@@ -12,10 +12,11 @@
#include "ipc.h"
#include "subcommands.h"
-int set_main(int argc, char *argv[])
+int set_main(int argc, char *argv[], struct wgoptions *options)
{
struct wgdevice *device = NULL;
int ret = 1;
+ (void)options;
if (argc < 3) {
fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
diff --git a/src/tools/setconf.c b/src/tools/setconf.c
index 012c245..c28dbac 100644
--- a/src/tools/setconf.c
+++ b/src/tools/setconf.c
@@ -13,7 +13,7 @@
#include "ipc.h"
#include "subcommands.h"
-int setconf_main(int argc, char *argv[])
+int setconf_main(int argc, char *argv[], struct wgoptions *options)
{
struct wgdevice *device = NULL;
struct config_ctx ctx;
@@ -21,6 +21,7 @@ int setconf_main(int argc, char *argv[])
char *config_buffer = NULL;
size_t config_buffer_len = 0;
int ret = 1;
+ (void)options;
if (argc != 3) {
fprintf(stderr, "Usage: %s %s <interface> <configuration filename>\n", PROG_NAME, argv[0]);
diff --git a/src/tools/show.c b/src/tools/show.c
index 9f98286..41f1a11 100644
--- a/src/tools/show.c
+++ b/src/tools/show.c
@@ -377,10 +377,11 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int
return true;
}
-int show_main(int argc, char *argv[])
+int show_main(int argc, char *argv[], struct wgoptions *options)
{
int ret = 0;
+ (void)options;
COMMAND_NAME = argv[0];
if (argc > 3) {
diff --git a/src/tools/showconf.c b/src/tools/showconf.c
index 313ad23..0c1fdc3 100644
--- a/src/tools/showconf.c
+++ b/src/tools/showconf.c
@@ -18,7 +18,7 @@
#include "ipc.h"
#include "subcommands.h"
-int showconf_main(int argc, char *argv[])
+int showconf_main(int argc, char *argv[], struct wgoptions *options)
{
char base64[WG_KEY_LEN_BASE64];
char ip[INET6_ADDRSTRLEN];
@@ -26,6 +26,7 @@ int showconf_main(int argc, char *argv[])
struct wgpeer *peer;
struct wgallowedip *allowedip;
int ret = 1;
+ (void)options;
if (argc != 2) {
fprintf(stderr, "Usage: %s %s <interface>\n", PROG_NAME, argv[0]);
diff --git a/src/tools/subcommands.h b/src/tools/subcommands.h
index c4aa4c6..8b10fd4 100644
--- a/src/tools/subcommands.h
+++ b/src/tools/subcommands.h
@@ -6,12 +6,14 @@
#ifndef SUBCOMMANDS_H
#define SUBCOMMANDS_H
+#include "containers.h"
+
extern const char *PROG_NAME;
-int show_main(int argc, char *argv[]);
-int showconf_main(int argc, char *argv[]);
-int set_main(int argc, char *argv[]);
-int setconf_main(int argc, char *argv[]);
-int genkey_main(int argc, char *argv[]);
-int pubkey_main(int argc, char *argv[]);
+int show_main(int argc, char *argv[], struct wgoptions *);
+int showconf_main(int argc, char *argv[], struct wgoptions *);
+int set_main(int argc, char *argv[], struct wgoptions *);
+int setconf_main(int argc, char *argv[], struct wgoptions *);
+int genkey_main(int argc, char *argv[], struct wgoptions *);
+int pubkey_main(int argc, char *argv[], struct wgoptions *);
#endif
diff --git a/src/tools/wg.c b/src/tools/wg.c
index 18a1480..3bf6252 100644
--- a/src/tools/wg.c
+++ b/src/tools/wg.c
@@ -6,14 +6,17 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
+#include <stdbool.h>
+#include <getopt.h>
#include "subcommands.h"
+#include "containers.h"
const char *PROG_NAME;
static const struct {
const char *subcommand;
- int (*function)(int, char**);
+ int (*function)(int, char**, struct wgoptions *);
const char *description;
} subcommands[] = {
{ "show", show_main, "Shows the current configuration and device information" },
@@ -35,26 +38,65 @@ static void show_usage(FILE *file)
fprintf(file, "You may pass `--help' to any of these subcommands to view usage.\n");
}
+static bool parse_options(int argc, char *argv[], struct wgoptions *options)
+{
+ int ch;
+ struct option opts[] = {
+ {
+ .name = "help",
+ .val = 'h',
+ },
+ {
+ 0
+ }
+ };
+ (void)options;
+
+ setenv("POSIXLY_CORRECT", "", 0);
+
+ while ((ch = getopt_long(argc, argv, "h", opts, NULL)) != -1) {
+ switch (ch) {
+ case '?':
+ return false;
+ case 'h':
+ show_usage(stdout);
+ exit(0);
+ }
+ }
+
+ return true;
+}
+
int main(int argc, char *argv[])
{
+ struct wgoptions options = { };
+
PROG_NAME = argv[0];
- if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "help"))) {
+ if (argc == 2 && !strcmp(argv[1], "help")) {
show_usage(stdout);
return 0;
}
- if (argc == 1) {
+ if (!parse_options(argc, argv, &options)) {
+ show_usage(stderr);
+ return 1;
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc == 0) {
static char *new_argv[] = { "show", NULL };
- return show_main(1, new_argv);
+ return show_main(1, new_argv, &options);
}
for (size_t i = 0; i < sizeof(subcommands) / sizeof(subcommands[0]); ++i) {
- if (!strcmp(argv[1], subcommands[i].subcommand))
- return subcommands[i].function(argc - 1, argv + 1);
+ if (!strcmp(argv[0], subcommands[i].subcommand))
+ return subcommands[i].function(argc, argv, &options);
}
- fprintf(stderr, "Invalid subcommand: `%s'\n", argv[1]);
+ fprintf(stderr, "Invalid subcommand: `%s'\n", argv[0]);
show_usage(stderr);
return 1;
}
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 10/12] tools: allow specifying the device namespace
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (8 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 09/12] tools: add framework for shared options Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 11/12] tools: allow modification of transit net Julian Orth
2018-09-11 19:13 ` [PATCH v3 12/12] tests: add test for transit-net Julian Orth
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
The user can now use
wg --netns <pid|file-path> <subcommand>
to specify the network namespace in which wg should act. This sets the
attribute WGDEVICE_A_DEV_NETNS_PID or WGDEVICE_A_DEV_NETNS_FD.
In the case of
wg --netns <pid|file-path> show all
we have to try to enter the network namespace because the kernel
interface does not allow us to list devices in a network namespace
referenced by pid or fd. Since entering a network namespace requires
CAP_SYS_ADMIN in the current user namespace and the target user
namespace, this is almost useless. TODO: Add the missing functionality
to the kernel.
---
src/tools/containers.h | 14 ++++++++++
src/tools/ipc.c | 22 +++++++++++----
src/tools/ipc.h | 7 +++--
src/tools/netns.c | 62 ++++++++++++++++++++++++++++++++++++++++++
src/tools/netns.h | 18 ++++++++++++
src/tools/set.c | 3 +-
src/tools/setconf.c | 3 +-
src/tools/show.c | 36 +++++++++++++++++-------
src/tools/showconf.c | 3 +-
src/tools/wg.c | 14 ++++++++--
10 files changed, 155 insertions(+), 27 deletions(-)
create mode 100644 src/tools/netns.c
create mode 100644 src/tools/netns.h
diff --git a/src/tools/containers.h b/src/tools/containers.h
index 8142d65..326071b 100644
--- a/src/tools/containers.h
+++ b/src/tools/containers.h
@@ -15,7 +15,21 @@
#include "../uapi/wireguard.h"
+struct wgnetns {
+ uint32_t flags;
+
+ uint32_t pid;
+ int fd;
+};
+
+enum {
+ WGNETNS_HAS_PID = 1U << 0,
+ WGNETNS_HAS_FD = 1U << 1,
+};
+
+
struct wgoptions {
+ struct wgnetns dev_netns;
};
struct wgallowedip {
diff --git a/src/tools/ipc.c b/src/tools/ipc.c
index e3ef789..6e0b4e7 100644
--- a/src/tools/ipc.c
+++ b/src/tools/ipc.c
@@ -544,7 +544,7 @@ cleanup:
return ret;
}
-static int kernel_set_device(struct wgdevice *dev)
+static int kernel_set_device(struct wgnetns *dev_netns, struct wgdevice *dev)
{
int ret = 0;
size_t i, j;
@@ -573,6 +573,10 @@ again:
mnl_attr_put_u32(nlh, WGDEVICE_A_FWMARK, dev->fwmark);
if (dev->flags & WGDEVICE_REPLACE_PEERS)
flags |= WGDEVICE_F_REPLACE_PEERS;
+ if (dev_netns->flags & WGNETNS_HAS_PID)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_DEV_NETNS_PID, dev_netns->pid);
+ if (dev_netns->flags & WGNETNS_HAS_FD)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_DEV_NETNS_FD, (uint32_t)dev_netns->fd);
if (flags)
mnl_attr_put_u32(nlh, WGDEVICE_A_FLAGS, flags);
}
@@ -879,7 +883,8 @@ static void coalesce_peers(struct wgdevice *device)
}
}
-static int kernel_get_device(struct wgdevice **device, const char *interface)
+static int kernel_get_device(struct wgnetns *dev_netns,
+ struct wgdevice **device, const char *interface)
{
int ret = 0;
struct nlmsghdr *nlh;
@@ -899,6 +904,10 @@ try_again:
nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, interface);
+ if (dev_netns->flags & WGNETNS_HAS_PID)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_DEV_NETNS_PID, dev_netns->pid);
+ if (dev_netns->flags & WGNETNS_HAS_FD)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_DEV_NETNS_FD, (uint32_t)dev_netns->fd);
if (mnlg_socket_send(nlg, nlh) < 0) {
ret = -errno;
goto out;
@@ -953,23 +962,24 @@ cleanup:
return buffer.buffer;
}
-int ipc_get_device(struct wgdevice **dev, const char *interface)
+int ipc_get_device(struct wgnetns *dev_netns, struct wgdevice **dev,
+ const char *interface)
{
#ifdef __linux__
if (userspace_has_wireguard_interface(interface))
return userspace_get_device(dev, interface);
- return kernel_get_device(dev, interface);
+ return kernel_get_device(dev_netns, dev, interface);
#else
return userspace_get_device(dev, interface);
#endif
}
-int ipc_set_device(struct wgdevice *dev)
+int ipc_set_device(struct wgnetns *dev_netns, struct wgdevice *dev)
{
#ifdef __linux__
if (userspace_has_wireguard_interface(dev->name))
return userspace_set_device(dev);
- return kernel_set_device(dev);
+ return kernel_set_device(dev_netns, dev);
#else
return userspace_set_device(dev);
#endif
diff --git a/src/tools/ipc.h b/src/tools/ipc.h
index 89e26cc..3ae2796 100644
--- a/src/tools/ipc.h
+++ b/src/tools/ipc.h
@@ -8,10 +8,13 @@
#include <stdbool.h>
+#include "containers.h"
+
struct wgdevice;
-int ipc_set_device(struct wgdevice *dev);
-int ipc_get_device(struct wgdevice **dev, const char *interface);
+int ipc_set_device(struct wgnetns *dev_netns, struct wgdevice *dev);
+int ipc_get_device(struct wgnetns *dev_netns, struct wgdevice **dev,
+ const char *interface);
char *ipc_list_devices(void);
#endif
diff --git a/src/tools/netns.c b/src/tools/netns.c
new file mode 100644
index 0000000..73ce762
--- /dev/null
+++ b/src/tools/netns.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018 Julian orth <ju.orth@gmail.com>. All Rights Reserved.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sched.h>
+#include <ctype.h>
+
+#include "netns.h"
+
+struct wgnetns netns_current = { 0 };
+
+bool netns_enter(struct wgnetns *netns)
+{
+ int fd = netns->fd;
+
+ if (!netns->flags)
+ return true;
+
+ if (netns->flags & WGNETNS_HAS_PID) {
+ char path[64];
+ sprintf(path, "/proc/%d/ns/net", netns->pid);
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ perror("Unable to open netns by pid");
+ return false;
+ }
+ }
+
+ if (setns(fd, CLONE_NEWNET)) {
+ perror("setns");
+ return false;
+ }
+
+ return true;
+}
+
+bool netns_parse(struct wgnetns *netns, const char *arg)
+{
+ /* U32 arg -> PID */
+ if (isdigit(*arg)) {
+ char *end;
+ unsigned long pid = strtoul(arg, &end, 10);
+ if (!*end && pid <= UINT32_MAX) {
+ netns->pid = pid;
+ netns->flags |= WGNETNS_HAS_PID;
+ return true;
+ }
+ }
+
+ /* Otherwise -> file path */
+ netns->fd = open(arg, O_RDONLY);
+ if (netns->fd >= 0) {
+ netns->flags |= WGNETNS_HAS_FD;
+ return true;
+ }
+
+ perror("open");
+ return false;
+}
diff --git a/src/tools/netns.h b/src/tools/netns.h
new file mode 100644
index 0000000..df7723a
--- /dev/null
+++ b/src/tools/netns.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018 Julian orth <ju.orth@gmail.com>. All Rights Reserved.
+ */
+
+#ifndef NETNS_H
+#define NETNS_H
+
+#include <stdbool.h>
+
+#include "containers.h"
+
+bool netns_enter(struct wgnetns *netns);
+bool netns_parse(struct wgnetns *netns, const char *arg);
+
+extern struct wgnetns netns_current;
+
+#endif
diff --git a/src/tools/set.c b/src/tools/set.c
index 2fb782b..24b72b8 100644
--- a/src/tools/set.c
+++ b/src/tools/set.c
@@ -16,7 +16,6 @@ int set_main(int argc, char *argv[], struct wgoptions *options)
{
struct wgdevice *device = NULL;
int ret = 1;
- (void)options;
if (argc < 3) {
fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
@@ -29,7 +28,7 @@ int set_main(int argc, char *argv[], struct wgoptions *options)
strncpy(device->name, argv[1], IFNAMSIZ - 1);
device->name[IFNAMSIZ - 1] = '\0';
- if (ipc_set_device(device) != 0) {
+ if (ipc_set_device(&options->dev_netns, device) != 0) {
perror("Unable to modify interface");
goto cleanup;
}
diff --git a/src/tools/setconf.c b/src/tools/setconf.c
index c28dbac..32543d7 100644
--- a/src/tools/setconf.c
+++ b/src/tools/setconf.c
@@ -21,7 +21,6 @@ int setconf_main(int argc, char *argv[], struct wgoptions *options)
char *config_buffer = NULL;
size_t config_buffer_len = 0;
int ret = 1;
- (void)options;
if (argc != 3) {
fprintf(stderr, "Usage: %s %s <interface> <configuration filename>\n", PROG_NAME, argv[0]);
@@ -51,7 +50,7 @@ int setconf_main(int argc, char *argv[], struct wgoptions *options)
strncpy(device->name, argv[1], IFNAMSIZ - 1);
device->name[IFNAMSIZ - 1] = '\0';
- if (ipc_set_device(device) != 0) {
+ if (ipc_set_device(&options->dev_netns, device) != 0) {
perror("Unable to modify interface");
goto cleanup;
}
diff --git a/src/tools/show.c b/src/tools/show.c
index 41f1a11..5ccb7f9 100644
--- a/src/tools/show.c
+++ b/src/tools/show.c
@@ -23,6 +23,7 @@
#include "terminal.h"
#include "encoding.h"
#include "subcommands.h"
+#include "netns.h"
static int peer_cmp(const void *first, const void *second)
{
@@ -377,17 +378,14 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int
return true;
}
-int show_main(int argc, char *argv[], struct wgoptions *options)
+static int show_all(int argc, char *argv[], struct wgoptions *options)
{
int ret = 0;
- (void)options;
- COMMAND_NAME = argv[0];
-
- if (argc > 3) {
- show_usage();
+ // The kernel interface used by ipc_list_devices does not allow us to
+ // list devices in a namespace referenced via pid or fd.
+ if (!netns_enter(&options->dev_netns))
return 1;
- }
if (argc == 1 || !strcmp(argv[1], "all")) {
char *interfaces = ipc_list_devices(), *interface;
@@ -401,7 +399,7 @@ int show_main(int argc, char *argv[], struct wgoptions *options)
for (size_t len = 0; (len = strlen(interface)); interface += len + 1) {
struct wgdevice *device = NULL;
- if (ipc_get_device(&device, interface) < 0) {
+ if (ipc_get_device(&netns_current, &device, interface) < 0) {
fprintf(stderr, "Unable to access interface %s: %s\n", interface, strerror(errno));
continue;
}
@@ -436,12 +434,30 @@ int show_main(int argc, char *argv[], struct wgoptions *options)
for (size_t len = 0; (len = strlen(interface)); interface += len + 1)
printf("%s%c", interface, strlen(interface + len + 1) ? ' ' : '\n');
free(interfaces);
- } else if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "help")))
+ }
+
+ return ret;
+}
+
+int show_main(int argc, char *argv[], struct wgoptions *options)
+{
+ int ret = 0;
+
+ COMMAND_NAME = argv[0];
+
+ if (argc > 3) {
+ show_usage();
+ return 1;
+ }
+
+ if (argc == 1 || !strcmp(argv[1], "all") || !strcmp(argv[1], "interfaces"))
+ ret = show_all(argc, argv, options);
+ else if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "help")))
show_usage();
else {
struct wgdevice *device = NULL;
- if (ipc_get_device(&device, argv[1]) < 0) {
+ if (ipc_get_device(&options->dev_netns, &device, argv[1]) < 0) {
perror("Unable to access interface");
return 1;
}
diff --git a/src/tools/showconf.c b/src/tools/showconf.c
index 0c1fdc3..a7d4053 100644
--- a/src/tools/showconf.c
+++ b/src/tools/showconf.c
@@ -26,14 +26,13 @@ int showconf_main(int argc, char *argv[], struct wgoptions *options)
struct wgpeer *peer;
struct wgallowedip *allowedip;
int ret = 1;
- (void)options;
if (argc != 2) {
fprintf(stderr, "Usage: %s %s <interface>\n", PROG_NAME, argv[0]);
return 1;
}
- if (ipc_get_device(&device, argv[1])) {
+ if (ipc_get_device(&options->dev_netns, &device, argv[1])) {
perror("Unable to access interface");
goto cleanup;
}
diff --git a/src/tools/wg.c b/src/tools/wg.c
index 3bf6252..3a81f74 100644
--- a/src/tools/wg.c
+++ b/src/tools/wg.c
@@ -11,6 +11,7 @@
#include "subcommands.h"
#include "containers.h"
+#include "netns.h"
const char *PROG_NAME;
@@ -46,21 +47,28 @@ static bool parse_options(int argc, char *argv[], struct wgoptions *options)
.name = "help",
.val = 'h',
},
+ {
+ .name = "netns",
+ .has_arg = 1,
+ .val = 'n',
+ },
{
0
}
};
- (void)options;
setenv("POSIXLY_CORRECT", "", 0);
- while ((ch = getopt_long(argc, argv, "h", opts, NULL)) != -1) {
+ while ((ch = getopt_long(argc, argv, "hn:", opts, NULL)) != -1) {
switch (ch) {
case '?':
return false;
case 'h':
show_usage(stdout);
exit(0);
+ case 'n':
+ netns_parse(&options->dev_netns, optarg);
+ break;
}
}
@@ -69,7 +77,7 @@ static bool parse_options(int argc, char *argv[], struct wgoptions *options)
int main(int argc, char *argv[])
{
- struct wgoptions options = { };
+ struct wgoptions options = { 0 };
PROG_NAME = argv[0];
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 11/12] tools: allow modification of transit net
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (9 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 10/12] tools: allow specifying the device namespace Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
2018-09-11 19:13 ` [PATCH v3 12/12] tests: add test for transit-net Julian Orth
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
The command is
wg set <device> [...] transit-netns <pid|file-path> [...]
For example:
wg set wg0 transit-netns 1
wg set wg0 transit-netns /proc/1/ns/net
---
src/tools/config.c | 8 ++++++++
src/tools/containers.h | 5 ++++-
src/tools/ipc.c | 4 ++++
src/tools/man/wg.8 | 9 +++++++--
src/tools/set.c | 2 +-
5 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/src/tools/config.c b/src/tools/config.c
index 93525fb..2424f3d 100644
--- a/src/tools/config.c
+++ b/src/tools/config.c
@@ -19,6 +19,7 @@
#include "containers.h"
#include "ipc.h"
#include "encoding.h"
+#include "netns.h"
#define COMMENT_CHAR '#'
@@ -392,6 +393,8 @@ static bool process_line(struct config_ctx *ctx, const char *line)
if (ctx->is_device_section) {
if (key_match("ListenPort"))
ret = parse_port(&ctx->device->listen_port, &ctx->device->flags, value);
+ else if (key_match("TransitNetns"))
+ ret = netns_parse(&ctx->device->transit_netns, value);
else if (key_match("FwMark"))
ret = parse_fwmark(&ctx->device->fwmark, &ctx->device->flags, value);
else if (key_match("PrivateKey")) {
@@ -525,6 +528,11 @@ struct wgdevice *config_read_cmd(char *argv[], int argc)
goto error;
argv += 2;
argc -= 2;
+ } else if (!strcmp(argv[0], "transit-netns") && argc >= 2 && !peer) {
+ if (!netns_parse(&device->transit_netns, argv[1]))
+ goto error;
+ argv += 2;
+ argc -= 2;
} else if (!strcmp(argv[0], "fwmark") && argc >= 2 && !peer) {
if (!parse_fwmark(&device->fwmark, &device->flags, argv[1]))
goto error;
diff --git a/src/tools/containers.h b/src/tools/containers.h
index 326071b..638c69c 100644
--- a/src/tools/containers.h
+++ b/src/tools/containers.h
@@ -75,7 +75,9 @@ enum {
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
- WGDEVICE_HAS_FWMARK = 1U << 4
+ WGDEVICE_HAS_FWMARK = 1U << 4,
+ WGDEVICE_HAS_TRANSIT_NETNS_PID = 1U << 5,
+ WGDEVICE_HAS_TRANSIT_NETNS_FD = 1U << 6,
};
struct wgdevice {
@@ -89,6 +91,7 @@ struct wgdevice {
uint32_t fwmark;
uint16_t listen_port;
+ struct wgnetns transit_netns;
struct wgpeer *first_peer, *last_peer;
};
diff --git a/src/tools/ipc.c b/src/tools/ipc.c
index 6e0b4e7..d88ace7 100644
--- a/src/tools/ipc.c
+++ b/src/tools/ipc.c
@@ -569,6 +569,10 @@ again:
mnl_attr_put(nlh, WGDEVICE_A_PRIVATE_KEY, sizeof(dev->private_key), dev->private_key);
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT)
mnl_attr_put_u16(nlh, WGDEVICE_A_LISTEN_PORT, dev->listen_port);
+ if (dev->transit_netns.flags & WGNETNS_HAS_PID)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_TRANSIT_NETNS_PID, dev->transit_netns.pid);
+ if (dev->transit_netns.flags & WGNETNS_HAS_FD)
+ mnl_attr_put_u32(nlh, WGDEVICE_A_TRANSIT_NETNS_FD, (uint32_t)dev->transit_netns.fd);
if (dev->flags & WGDEVICE_HAS_FWMARK)
mnl_attr_put_u32(nlh, WGDEVICE_A_FWMARK, dev->fwmark);
if (dev->flags & WGDEVICE_REPLACE_PEERS)
diff --git a/src/tools/man/wg.8 b/src/tools/man/wg.8
index 5bae7ca..d1f95f7 100644
--- a/src/tools/man/wg.8
+++ b/src/tools/man/wg.8
@@ -55,12 +55,17 @@ transfer-rx, transfer-tx, persistent-keepalive.
Shows the current configuration of \fI<interface>\fP in the format described
by \fICONFIGURATION FILE FORMAT\fP below.
.TP
-\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
+\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fItransit-netns\fP \fI<pid|file-path>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
Sets configuration values for the specified \fI<interface>\fP. Multiple
\fIpeer\fPs may be specified, and if the \fIremove\fP argument is given
for a peer, that peer is removed, not configured. If \fIlisten-port\fP
is not specified, the port will be chosen randomly when the
-interface comes up. Both \fIprivate-key\fP and \fIpreshared-key\fP must
+interface comes up. If transit-netns is not specified, the network namespace
+through which encrypted packets are routed is the one in which the device
+was created. Otherwise the network namespace through which encrypted packets are
+routed is the one specified by the argument. If the argument is an unsigned
+32-bit integer, it is interpeted as a process id, otherwise it is interpreted as
+a file path. Both \fIprivate-key\fP and \fIpreshared-key\fP must
be a files, because command line arguments are not considered private on
most systems but if you are using
.BR bash (1),
diff --git a/src/tools/set.c b/src/tools/set.c
index 24b72b8..f22d86b 100644
--- a/src/tools/set.c
+++ b/src/tools/set.c
@@ -18,7 +18,7 @@ int set_main(int argc, char *argv[], struct wgoptions *options)
int ret = 1;
if (argc < 3) {
- fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
+ fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [transit-netns <pid|file path>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
return 1;
}
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v3 12/12] tests: add test for transit-net
2018-09-11 19:12 [PATCH v3 00/12] Allow changing the transit namespace Julian Orth
` (10 preceding siblings ...)
2018-09-11 19:13 ` [PATCH v3 11/12] tools: allow modification of transit net Julian Orth
@ 2018-09-11 19:13 ` Julian Orth
11 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-09-11 19:13 UTC (permalink / raw)
To: wireguard
---
src/tests/netns.sh | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/src/tests/netns.sh b/src/tests/netns.sh
index 568612c..4cc6b44 100755
--- a/src/tests/netns.sh
+++ b/src/tests/netns.sh
@@ -222,6 +222,46 @@ n1 wg set wg0 peer "$more_specific_key" remove
ip1 link del wg0
ip2 link del wg0
+# Test using transit namespace. We now change the topology to this with transit-netns of $ns1 wg0 = $ns0
+# ┌──────────────────────┐ ┌───────────────────────┐ ┌────────────────────────────────────────┐
+# │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │
+# │ │ │ │ │ │
+# │ ┌─────┐ │ │ ┌──────┐ │ │ ┌─────┐ ┌─────┐ │
+# │ │ wg0 │ │ │ │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │ │
+# │ ├─────┴──────────┐ │ │ ├──────┴────────────┐ │ │ ├─────┴──────────┐ ├─────┴──────────┐ │
+# │ │192.168.241.1/24│ │ │ │10.0.0.1/24 │ │ │ │10.0.0.100/24 │ │192.168.241.2/24│ │
+# │ │fd00::1/24 │ │ │ │SNAT:192.168.1.0/24│ │ │ │ │ │fd00::2/24 │ │
+# │ └────────────────┘ │ │ └───────────────────┘ │ │ └────────────────┘ └────────────────┘ │
+# └──────────────────────┘ └───────────────────────┘ └────────────────────────────────────────┘
+
+ip1 link add dev wg0 type wireguard
+ip2 link add dev wg0 type wireguard
+configure_peers
+n1 wg set wg0 transit-netns /run/netns/$netns0
+
+ip0 link add vethrs type veth peer name veths
+ip0 link set veths netns $netns2
+ip0 link set vethrs up
+ip0 addr add 10.0.0.1/24 dev vethrs
+ip2 addr add 10.0.0.100/24 dev veths
+ip1 route add default dev wg0
+ip2 link set veths up
+waitiface $netns0 vethrs
+waitiface $netns2 veths
+
+n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
+n1 ping -W 1 -c 1 192.168.241.2
+n2 ping -W 1 -c 1 192.168.241.1
+[[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]]
+# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
+pp sleep 3
+n2 ping -W 1 -c 1 192.168.241.1
+
+ip0 link del vethrs
+
+ip1 link del wg0
+ip2 link del wg0
+
# Test using NAT. We now change the topology to this:
# ┌────────────────────────────────────────┐ ┌────────────────────────────────────────────────┐ ┌────────────────────────────────────────┐
# │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │
--
2.18.0
^ permalink raw reply related [flat|nested] 13+ messages in thread