wireguard.lists.zx2c4.com archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/11] Allow changing the transit namespace
@ 2018-12-15 16:56 Julian Orth
  2018-12-15 16:56 ` [PATCH v5 01/11] netlink: check for CAP_NET_ADMIN manually Julian Orth
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 UTC (permalink / raw)
  To: wireguard

Hi,

This is v5 of this series. This series makes the following changes:

* wg(1) can now access devices in another network namespace. The syntax
  is
    
    wg --netns <pid|file-path> <subcommand>

  For example

    wg --netns 5363 show wg0

* wg(1) can now change the network namespace of the UDP socket of a
  device. The syntax is

    wg set <device> transit-netns <pid|file-path>

  For example

    wg set wg0 transit-netns 5363

* When retrieving or modifying properties of the UDP socket (its
  incoming port or its network namespace), the netlink code now checks
  that the calling process has at least one of the following properties:

  * The calling process' network namespace is the same as the (new)
    network namespace of the socket.
  * The calling process has the CAP_NET_ADMIN capability in the (new)
    network namespace of the socket.

These changes allow a user to create a wg device in a user namespace and
to set the network namespace of the UDP socket to the init namespace.
This allows the user to communicate over a wg device even if the user
does not have root in the init namespace.

The code of this version is almost identical to the previous version
except that

* the first commit has been dropped and
* the code has been rebased on master.

Julian

Julian Orth (11):
  netlink: check for CAP_NET_ADMIN manually
  netlink: allow specifying the device namespace
  netlink: restrict access to the UDP socket
  device: rename creating_net to transit_net
  device: store a copy of the device net
  socket: allow modification of transit_net
  netlink: allow modification of transit net
  tools: add framework for shared options
  tools: allow specifying the device namespace
  tools: allow modification of transit net
  tests: add test for transit-net

 src/device.c            |  35 ++++++----
 src/device.h            |   6 +-
 src/netlink.c           | 150 ++++++++++++++++++++++++++++++++--------
 src/socket.c            |  18 ++---
 src/socket.h            |   6 +-
 src/tests/netns.sh      |  40 +++++++++++
 src/tools/config.c      |   8 +++
 src/tools/containers.h  |  22 +++++-
 src/tools/genkey.c      |   3 +-
 src/tools/ipc.c         |  26 +++++--
 src/tools/ipc.h         |   7 +-
 src/tools/man/wg.8      |   9 ++-
 src/tools/netns.c       |  62 +++++++++++++++++
 src/tools/netns.h       |  18 +++++
 src/tools/pubkey.c      |   3 +-
 src/tools/set.c         |   6 +-
 src/tools/setconf.c     |   4 +-
 src/tools/show.c        |  35 +++++++---
 src/tools/showconf.c    |   4 +-
 src/tools/subcommands.h |  14 ++--
 src/tools/wg.c          |  64 +++++++++++++++--
 src/uapi/wireguard.h    |  39 ++++++++++-
 22 files changed, 477 insertions(+), 102 deletions(-)
 create mode 100644 src/tools/netns.c
 create mode 100644 src/tools/netns.h

-- 
2.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v5 01/11] netlink: check for CAP_NET_ADMIN manually
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 02/11] netlink: allow specifying the device namespace Julian Orth
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 18bebb8..364d4d8 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -163,6 +163,7 @@ err:
 static int wg_get_device_start(struct netlink_callback *cb)
 {
 	struct nlattr **attrs = genl_family_attrbuf(&genl_family);
+	struct net *dev_net = sock_net(cb->skb->sk);
 	struct wg_device *wg;
 	int ret;
 
@@ -170,6 +171,8 @@ static int wg_get_device_start(struct netlink_callback *cb)
 			  genl_family.maxattr, device_policy, 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]))
@@ -470,9 +473,17 @@ out:
 
 static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
 {
-	struct wg_device *wg = lookup_interface(info->attrs, skb);
+	struct net *dev_net = sock_net(skb->sk);
+	struct wg_device *wg;
 	int ret;
 
+	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);
 		goto out_nodev;
@@ -574,12 +585,10 @@ struct genl_ops genl_ops[] = {
 		.dumpit = wg_get_device_dump,
 		.done = wg_get_device_done,
 		.policy = device_policy,
-		.flags = GENL_UNS_ADMIN_PERM
 	}, {
 		.cmd = WG_CMD_SET_DEVICE,
 		.doit = wg_set_device,
 		.policy = device_policy,
-		.flags = GENL_UNS_ADMIN_PERM
 	}
 };
 
-- 
2.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 02/11] netlink: allow specifying the device namespace
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
  2018-12-15 16:56 ` [PATCH v5 01/11] netlink: check for CAP_NET_ADMIN manually Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 03/11] netlink: restrict access to the UDP socket Julian Orth
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 364d4d8..96ad555 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 wg_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);
@@ -160,10 +162,22 @@ 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 wg_get_device_start(struct netlink_callback *cb)
 {
 	struct nlattr **attrs = genl_family_attrbuf(&genl_family);
-	struct net *dev_net = sock_net(cb->skb->sk);
+	struct net *owned_dev_net = NULL, *dev_net;
+	struct allowedips_cursor *cursor = NULL;
 	struct wg_device *wg;
 	int ret;
 
@@ -171,20 +185,42 @@ static int wg_get_device_start(struct netlink_callback *cb)
 			  genl_family.maxattr, device_policy, 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 wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@ -473,16 +509,23 @@ out:
 
 static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
 {
-	struct net *dev_net = sock_net(skb->sk);
+	struct net *owned_dev_net, *dev_net;
 	struct wg_device *wg;
 	int ret;
 
+	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(owned_dev_net);
+		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);
@@ -565,6 +608,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 0203f2c..bcfcf4f 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 03/11] netlink: restrict access to the UDP socket
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
  2018-12-15 16:56 ` [PATCH v5 01/11] netlink: check for CAP_NET_ADMIN manually Julian Orth
  2018-12-15 16:56 ` [PATCH v5 02/11] netlink: allow specifying the device namespace Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 04/11] device: rename creating_net to transit_net Julian Orth
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 96ad555..e17c3e1 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -173,6 +173,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 wg_get_device_start(struct netlink_callback *cb)
 {
 	struct nlattr **attrs = genl_family_attrbuf(&genl_family);
@@ -249,9 +257,12 @@ static int wg_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;
@@ -338,7 +349,11 @@ static int wg_get_device_done(struct netlink_callback *cb)
 static int set_port(struct wg_device *wg, u16 port)
 {
 	struct wg_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 bcfcf4f..8b60ad1 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 04/11] device: rename creating_net to transit_net
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (2 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 03/11] netlink: restrict access to the UDP socket Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 05/11] device: store a copy of the device net Julian Orth
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 877000b..ae4b9ad 100644
--- a/src/device.c
+++ b/src/device.c
@@ -251,8 +251,8 @@ static void wg_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);
@@ -304,7 +304,7 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
 	struct wg_device *wg = netdev_priv(dev);
 	int ret = -ENOMEM;
 
-	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);
@@ -406,13 +406,13 @@ static int wg_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 b0cbc78..be54d4a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -40,7 +40,7 @@ struct wg_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 wg_device {
 	unsigned int num_peers, device_update_gen;
 	u32 fwmark;
 	u16 incoming_port;
-	bool have_creating_net_ref;
+	bool have_transit_net_ref;
 };
 
 int wg_device_init(void);
diff --git a/src/netlink.c b/src/netlink.c
index e17c3e1..8d22230 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -257,7 +257,7 @@ static int wg_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;
@@ -351,7 +351,7 @@ static int set_port(struct wg_device *wg, u16 port)
 	struct wg_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 2752335..75e4114 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -382,18 +382,18 @@ int wg_socket_init(struct wg_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)
@@ -403,7 +403,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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 05/11] device: store a copy of the device net
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (3 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 04/11] device: rename creating_net to transit_net Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 06/11] socket: allow modification of transit_net Julian Orth
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 ae4b9ad..0c0c17b 100644
--- a/src/device.c
+++ b/src/device.c
@@ -251,7 +251,7 @@ static void wg_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);
 
@@ -304,7 +304,9 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
 	struct wg_device *wg = netdev_priv(dev);
 	int ret = -ENOMEM;
 
-	wg->transit_net = src_net;
+	wg->dev_net = NULL;
+	wg->transit_net = NULL;
+	wg_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);
@@ -406,14 +408,8 @@ static int wg_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);
-	}
+	wg_device_set_nets(wg, dev_net(dev), wg->transit_net);
+
 	return 0;
 }
 
@@ -459,3 +455,14 @@ void wg_device_uninit(void)
 #endif
 	rcu_barrier_bh();
 }
+
+void wg_device_set_nets(struct wg_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 be54d4a..e1d4e84 100644
--- a/src/device.h
+++ b/src/device.h
@@ -41,6 +41,7 @@ struct wg_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 wg_device {
 	unsigned int num_peers, device_update_gen;
 	u32 fwmark;
 	u16 incoming_port;
-	bool have_transit_net_ref;
 };
 
 int wg_device_init(void);
 void wg_device_uninit(void);
+void wg_device_set_nets(struct wg_device *wg, struct net *dev_net,
+			struct net *transit_net);
 
 #endif /* _WG_DEVICE_H */
-- 
2.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 06/11] socket: allow modification of transit_net
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (4 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 05/11] device: store a copy of the device net Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 07/11] netlink: allow modification of transit net Julian Orth
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 UTC (permalink / raw)
  To: wireguard

---
 src/device.c  |  6 +++---
 src/netlink.c |  2 +-
 src/socket.c  | 18 ++++++++++--------
 src/socket.h  |  6 +++---
 4 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/src/device.c b/src/device.c
index 0c0c17b..18b4587 100644
--- a/src/device.c
+++ b/src/device.c
@@ -53,7 +53,7 @@ static int wg_open(struct net_device *dev)
 #endif
 #endif
 
-	ret = wg_socket_init(wg, wg->incoming_port);
+	ret = wg_socket_init(wg, wg->transit_net, wg->incoming_port);
 	if (ret < 0)
 		return ret;
 	mutex_lock(&wg->device_update_lock);
@@ -118,7 +118,7 @@ static int wg_stop(struct net_device *dev)
 	}
 	mutex_unlock(&wg->device_update_lock);
 	skb_queue_purge(&wg->incoming_handshakes);
-	wg_socket_reinit(wg, NULL, NULL);
+	wg_socket_reinit(wg, NULL, NULL, NULL);
 	return 0;
 }
 
@@ -236,7 +236,7 @@ static void wg_destruct(struct net_device *dev)
 	rtnl_unlock();
 	mutex_lock(&wg->device_update_lock);
 	wg->incoming_port = 0;
-	wg_socket_reinit(wg, NULL, NULL);
+	wg_socket_reinit(wg, NULL, NULL, NULL);
 	wg_allowedips_free(&wg->peer_allowedips, &wg->device_update_lock);
 	/* The final references are cleared in the below calls to destroy_workqueue. */
 	wg_peer_remove_all(wg);
diff --git a/src/netlink.c b/src/netlink.c
index 8d22230..e0f3632 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -362,7 +362,7 @@ static int set_port(struct wg_device *wg, u16 port)
 		wg->incoming_port = port;
 		return 0;
 	}
-	return wg_socket_init(wg, port);
+	return wg_socket_init(wg, wg->transit_net, port);
 }
 
 static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
diff --git a/src/socket.c b/src/socket.c
index 75e4114..1ac065f 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -352,7 +352,7 @@ static void set_sock_opts(struct socket *sock)
 	sk_set_memalloc(sock->sk);
 }
 
-int wg_socket_init(struct wg_device *wg, u16 port)
+int wg_socket_init(struct wg_device *wg, struct net *net, u16 port)
 {
 	int ret;
 	struct udp_tunnel_sock_cfg cfg = {
@@ -382,18 +382,18 @@ int wg_socket_init(struct wg_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)
@@ -403,16 +403,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
 
-	wg_socket_reinit(wg, new4 ? new4->sk : NULL, new6 ? new6->sk : NULL);
+	wg_socket_reinit(wg, net, new4 ? new4->sk : NULL, new6 ? new6->sk : NULL);
 	return 0;
 }
 
-void wg_socket_reinit(struct wg_device *wg, struct sock *new4,
-		      struct sock *new6)
+void wg_socket_reinit(struct wg_device *wg, struct net *net,
+		      struct sock *new4, struct sock *new6)
 {
 	struct sock *old4, *old6;
 
@@ -425,6 +425,8 @@ void wg_socket_reinit(struct wg_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)
+		wg_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 9d3e8e1..2db1f86 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -11,9 +11,9 @@
 #include <linux/if_vlan.h>
 #include <linux/if_ether.h>
 
-int wg_socket_init(struct wg_device *wg, u16 port);
-void wg_socket_reinit(struct wg_device *wg, struct sock *new4,
-		      struct sock *new6);
+int wg_socket_init(struct wg_device *wg, struct net *net, u16 port);
+void wg_socket_reinit(struct wg_device *wg, struct net *net,
+		      struct sock *new4, struct sock *new6);
 int wg_socket_send_buffer_to_peer(struct wg_peer *peer, void *data,
 				  size_t len, u8 ds);
 int wg_socket_send_skb_to_peer(struct wg_peer *peer, struct sk_buff *skb,
-- 
2.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 07/11] netlink: allow modification of transit net
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (5 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 06/11] socket: allow modification of transit_net Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-17 14:52   ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 08/11] tools: add framework for shared options Julian Orth
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 e0f3632..f5c3a9e 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] = {
@@ -346,23 +348,44 @@ static int wg_get_device_done(struct netlink_callback *cb)
 	return 0;
 }
 
-static int set_port(struct wg_device *wg, u16 port)
+static int set_socket(struct wg_device *wg, struct nlattr **attrs)
 {
 	struct wg_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)
 		wg_socket_clear_peer_endpoint_src(peer);
 	if (!netif_running(wg->dev)) {
 		wg->incoming_port = port;
-		return 0;
+		if (net)
+			wg_device_set_nets(wg, wg->dev_net, net);
+		goto out;
 	}
-	return wg_socket_init(wg, wg->transit_net, port);
+	ret = wg_socket_init(wg, net ? : wg->transit_net, port);
+
+out:
+	if (net)
+		put_net(net);
+	return ret;
 }
 
 static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
@@ -559,12 +582,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_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 8b60ad1..5eabe22 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 08/11] tools: add framework for shared options
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (6 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 07/11] netlink: allow modification of transit net Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 09/11] tools: allow specifying the device namespace Julian Orth
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 619094e..cd757e4 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 e50d64b..d286cc0 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 cf8e256..08a3e9a 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 9d84ccd..4e90940 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 7135e85..8133bdd 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 b50af2a..1ebe6e2 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 777e022..1de65b0 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 2a7e36e..6707ead 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 4c24ff0..f70b5c5 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 09/11] tools: allow specifying the device namespace
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (7 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 08/11] tools: add framework for shared options Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 10/11] tools: allow modification of transit net Julian Orth
  2018-12-15 16:56 ` [PATCH v5 11/11] tests: add test for transit-net Julian Orth
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 cd757e4..d588a44 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 5879109..2c16897 100644
--- a/src/tools/ipc.c
+++ b/src/tools/ipc.c
@@ -551,7 +551,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;
 	struct wgpeer *peer = NULL;
@@ -579,6 +579,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);
 	}
@@ -885,7 +889,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;
@@ -905,6 +910,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;
@@ -959,23 +968,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 e75be20..4cb7dca 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 4e90940..5457c67 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 8133bdd..cf224fe 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 1ebe6e2..bfd07e6 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 1de65b0..239968c 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 f70b5c5..1fd8157 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 10/11] tools: allow modification of transit net
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (8 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 09/11] tools: allow specifying the device namespace Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  2018-12-15 16:56 ` [PATCH v5 11/11] tests: add test for transit-net Julian Orth
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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 1daa5ea..76a74f2 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 d588a44..ce812e9 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 2c16897..e66cd2c 100644
--- a/src/tools/ipc.c
+++ b/src/tools/ipc.c
@@ -575,6 +575,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 2013825..0ddad87 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 5457c67..f11ef8f 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v5 11/11] tests: add test for transit-net
  2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
                   ` (9 preceding siblings ...)
  2018-12-15 16:56 ` [PATCH v5 10/11] tools: allow modification of transit net Julian Orth
@ 2018-12-15 16:56 ` Julian Orth
  10 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-15 16:56 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.19.2

_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v5 07/11] netlink: allow modification of transit net
  2018-12-15 16:56 ` [PATCH v5 07/11] netlink: allow modification of transit net Julian Orth
@ 2018-12-17 14:52   ` Julian Orth
  0 siblings, 0 replies; 13+ messages in thread
From: Julian Orth @ 2018-12-17 14:52 UTC (permalink / raw)
  To: WireGuard mailing list

On 12/15/18 5:56 PM, Julian Orth wrote:
> +	ret = test_socket_net_capable(net ? : wg->transit_net);
I forgot to include the fix mentioned in [1]. I have fixed the commit in the
repository and I'll include the diff below.

diff --git a/src/netlink.c b/src/netlink.c
index f5c3a9e..90ff936 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -350,14 +350,20 @@ static int wg_get_device_done(struct netlink_callback *cb)

 static int set_socket(struct wg_device *wg, struct nlattr **attrs)
 {
-	struct wg_peer *peer;
-	struct nlattr *port_attr = attrs[WGDEVICE_A_LISTEN_PORT];
-	u16 port;
+	struct nlattr *netns_pid_attr, *netns_fd_attr, *port_attr;
 	struct net *net = NULL;
+	struct wg_peer *peer;
 	int ret = 0;
+	u16 port;
+
+	netns_pid_attr = attrs[WGDEVICE_A_TRANSIT_NETNS_PID];
+	netns_fd_attr = attrs[WGDEVICE_A_TRANSIT_NETNS_FD];
+	port_attr = attrs[WGDEVICE_A_LISTEN_PORT];
+
+	if (!netns_pid_attr && !netns_fd_attr && !port_attr)
+		return 0;

-	net = get_attr_net(attrs[WGDEVICE_A_TRANSIT_NETNS_PID],
-			attrs[WGDEVICE_A_TRANSIT_NETNS_FD]);
+	net = get_attr_net(netns_pid_attr, netns_fd_attr);
 	if (IS_ERR(net))
 		return PTR_ERR(net);
 	if (port_attr)

[1] https://lists.zx2c4.com/pipermail/wireguard/2018-October/003459.html
_______________________________________________
WireGuard mailing list
WireGuard@lists.zx2c4.com
https://lists.zx2c4.com/mailman/listinfo/wireguard

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2018-12-17 14:52 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-15 16:56 [PATCH v5 00/11] Allow changing the transit namespace Julian Orth
2018-12-15 16:56 ` [PATCH v5 01/11] netlink: check for CAP_NET_ADMIN manually Julian Orth
2018-12-15 16:56 ` [PATCH v5 02/11] netlink: allow specifying the device namespace Julian Orth
2018-12-15 16:56 ` [PATCH v5 03/11] netlink: restrict access to the UDP socket Julian Orth
2018-12-15 16:56 ` [PATCH v5 04/11] device: rename creating_net to transit_net Julian Orth
2018-12-15 16:56 ` [PATCH v5 05/11] device: store a copy of the device net Julian Orth
2018-12-15 16:56 ` [PATCH v5 06/11] socket: allow modification of transit_net Julian Orth
2018-12-15 16:56 ` [PATCH v5 07/11] netlink: allow modification of transit net Julian Orth
2018-12-17 14:52   ` Julian Orth
2018-12-15 16:56 ` [PATCH v5 08/11] tools: add framework for shared options Julian Orth
2018-12-15 16:56 ` [PATCH v5 09/11] tools: allow specifying the device namespace Julian Orth
2018-12-15 16:56 ` [PATCH v5 10/11] tools: allow modification of transit net Julian Orth
2018-12-15 16:56 ` [PATCH v5 11/11] tests: add test for transit-net Julian Orth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).