I have a wireguard connection (interface name wg0
) to a trusted machine inside an admin network at $DAYJOB. Usually, I don't want to use wg0 for all my traffic, only for IP addresses in the 172.16.0.0/12 range. This is easily accomplished with a stanza like so in /etc/wireguard/wg0.conf
:
[Peer]
# ...
AllowedIPs = 172.16.0.0/12
But for one firefox profile, I do want to route everything through wg0, even traffic not destined for 172.16.0.0/12. Furthermore, for DNS, I usually use dnscrypt-proxy + dnsmasq, but for wg0 traffic I want to use the nameserver at $DAYJOB.
I can almost match these constraints by having a network namespace created with ip netns
and a veth pair. Inside the namespace, simply replace my default resolv.conf with one containing the alternative nameserver. The only problem is that I haven't quite figured out how to use wg0 as the sole way for packets to leave the namespace.
- Non-default DNS used: ✓
- Traffic from the namespace destined for 172.16.0.0/12 is correctly routed through wg0: ✓
- All other traffic exiting the namespace also goes via wg0: ✗
Wireguard has documentation related to netns but it seems to assume you don't still need the wireguard interface outside the namespace. I do want everything outside the namespace to still have access to the wireguard interface.
Some sources, eg 1, suggest something similar using vlans. However, it seems like wireguard interfaces do not support vlans. Here is what happens:
$ sudo ip link add link wg0 name wg0.4 type vlan id 4
$ sudo ip netns add ns-wg-test-1
$ sudo ip link set wg0.4 netns ns-wg-test-1
$ sudo ip netns exec ns-wg-test-1 su -c "/bin/bash -l" $USER
$ sudo ip addr add 192.168.126.2 dev wg0.4
$ sudo ip link set dev wg0.4 up
RTNETLINK answers: Cannot assign requested address
So now I'm equivocating between various alternative approaches which all have problems.
Possibility 1: Add a second wireguard interface. That will require making a bunch of redundant configs in /etc/wireguard/wg1.conf
. It's not clear that this is even workable or a good idea. It seems inelegant to have multiple wireguard interfaces and redundant configs.
Possibility 2: Add some combination of ip route
and iptables -A
rules to force everything exiting the namespace to then be channelled into wg0. However, I haven't come across any examples or documentation which makes it clear how to force the routing of all traffic incoming from one interface to go out via another interface. And again, I have a certain amount of skepticism that this would even be a good approach.
Possibility 3: Have faith in the wireguard documentation. Put wg0 inside the namespace, and tell all 172.16.0.0/12 traffic outside the namespace to go via a veth pair connected to the namespace. Inside the namespace, there could be routing/firewall rules to forward everything from the veth pair to wg0. The problem with this solution is that, even if it works, it requires the namespace to always be active. I would like traffic destined for 172.16.0.0/12 to always find its way to wg0 regardless of whether I remembered to activate the namespace this morning.
So the question is: what is the best or most canonical way to share a wireguard interface with a network namespace, while still retaining access to wireguard outside of the namespace?
This isn't opinion-based. I'll know the answer is right when I can see a working example which is robust, efficient, secure, and scriptable. It doesn't need to be cross-platform. I am doing this solely on Void Linux (or sometimes Arch Linux).
Alternatively, if the whole enterprise is not a good idea, or not possible for some reason, a negative answer could consist of arguments, evidence, and citations to explain why. I'll still mark it as correct if nothing better comes along.