Routing & Network Namespaces - WireGuard (2024)

Routing & Network Namespace Integration

Like all Linux network interfaces, WireGuard integrates into the network namespace infrastructure. This means an administrator can have several entirely different networking subsystems and choose which interfaces live in each.

WireGuard does something quite interesting. When a WireGuard interface is created (with ip link add wg0 type wireguard), it remembers the namespace in which it was created. "I was created in namespace A." Later, WireGuard can be moved to new namespaces ("I'm moving to namespace B."), but it will still remember that it originated in namespace A.

WireGuard uses a UDP socket for actually sending and receiving encrypted packets. This socket always lives in namespace A – the original birthplace namespace. This allows for some very cool properties. Namely, you can create the WireGuard interface in one namespace (A), move it to another (B), and have cleartext packets sent from namespace B get sent encrypted through a UDP socket in namespace A.

(Note that this same technique is available to userspace TUN-based interfaces, by creating a socket file-descriptor in one namespace, before changing to another namespace and keeping the file-descriptor from the previous namespace open.)

This opens up some very nice possibilities.

Ordinary Containerization

The most obvious usage of this is to give containers (like Docker containers, for example) a WireGuard interface as its sole interface.

container # ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever17: wg0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1423 qdisc noqueue state UNKNOWN group default qlen 1 link/none inet 192.168.4.33/32 scope global wg0 valid_lft forever preferred_lft forever

Here, the only way of accessing the network possible is through wg0, the WireGuard interface.

Routing & Network Namespaces - WireGuard (1)

The way to accomplish a setup like this is as follows:

First we create the network namespace called "container":

# ip netns add container

Next, we create a WireGuard interface in the "init" (original) namespace:

# ip link add wg0 type wireguard

Finally, we move that interface into the new namespace:

# ip link set wg0 netns container

Now we can configure wg0 as usual, except we specify its new namespace in doing so:

# ip -n container addr add 192.168.4.33/32 dev wg0# ip netns exec container wg setconf wg0 /etc/wireguard/wg0.conf# ip -n container link set wg0 up# ip -n container route add default dev wg0

And voila, now the only way of accessing any network resources for "container" will be via the WireGuard interface.

Note that Docker users can specify the PID of a Docker process instead of the network namespace name, to use the network namespace that Docker already created for its container:

# ip link set wg0 netns 879

Routing All Your Traffic

A less obvious usage, but extremely powerful nonetheless, is to use this characteristic of WireGuard for redirecting all of your ordinary Internet traffic over WireGuard. But first, let's review the old usual solutions for doing this:

The Classic Solutions

The classic solutions rely on different types of routing table configurations. For all of these, we need to set some explicit route for the actual WireGuard endpoint. For these examples, let's assume the WireGuard endpoint is demo.wireguard.com, which, as of writing, resolves to 163.172.161.0. Further, let's assume we usually connect to the Internet using eth0 and the classic gateway of 192.168.1.1.

Replacing The Default Route

The most straightforward technique is to just replace the default route, but add an explicit rule for the WireGuard endpoint:

# ip route del default# ip route add default dev wg0# ip route add 163.172.161.0/32 via 192.168.1.1 dev eth0

This works and is relatively straightforward, but DHCP daemons and such like to undo what we've just did, unfortunately.

Overriding The Default Route

So, instead of replacing the default route, we can just override it with two more specific rules that add up in sum to the default, but match before the default:

# ip route add 0.0.0.0/1 dev wg0# ip route add 128.0.0.0/1 dev wg0# ip route add 163.172.161.0/32 via 192.168.1.1 dev eth0

This way, we don't clobber the default route. This also works quite well, though, unfortunately when eth0 goes up and down, the explicit route for demo.wireguard.com will be forgotten, which is annoying.

Rule-based Routing

Some folks prefer to use rule-based routing and multiple routing tables. The way this works is we create one routing table for WireGuard routes and one routing table for plaintext Internet routes, and then add rules to determine which routing table to use for each:

# ip rule add to 163.172.161.0 lookup main pref 30# ip rule add to all lookup 80 pref 40# ip route add default dev wg0 table 80

Now, we're able to to keep the routing tables separate. Unfortunately the downside is that explicit endpoint rules still need to be added, and there's no cleanup when the interface is removed, and more complicated routing rules now need to be duplicated.

Improved Rule-based Routing

The prior solution relies on us knowing the explicit endpoint IP that should be exempt from the tunnel, but WireGuard endpoints can roam, which means this rule may go stale. Fortunately, we are able to set an fwmark on all packets going out of WireGuard's UDP socket, which will then be exempt from the tunnel:

# wg set wg0 fwmark 1234# ip route add default dev wg0 table 2468# ip rule add not fwmark 1234 table 2468# ip rule add table main suppress_prefixlength 0

We first set the fwmark on the interface and set a default route on an alternative routing table. Then we indicate that packets that do not have the fwmark should go to this alternative routing table. And finally we add a convenience feature for still accessing the local network, whereby we allow packets without the fwmark to use the main routing table, not the WireGuard interface's routing table, if it matches any routes in it with a prefix length greater than zero, such as non-default local routes. This is the technique used by the wg-quick(8) tool.

Improving the Classic Solutions

The WireGuard authors are interested in adding a feature called "notoif" to the kernel to cover tunnel use cases. This would allow interfaces to say "do not route this packet using myself as an interface, to avoid the routing loop". WireGuard would be able to add a line like .flowi4_not_oif = wg0_idx, and userspace tun-based interfaces would be able to set an option on their outgoing socket like setsockopt(fd, SO_NOTOIF, tun0_idx);. Unfortuantely this hasn't yet been merged, but you can read the LKML thread here.

The New Namespace Solution

It turns out that we can route all Internet traffic via WireGuard using network namespaces, rather than the classic routing table hacks. The way this works is that we move interfaces that connect to the Internet, like eth0 or wlan0, to a namespace (which we call "physical"), and then have a WireGuard interface be the sole interface in the "init" namespace.

Routing & Network Namespaces - WireGuard (2)

First we create the "physical" network namespace:

# ip netns add physical

Now we move eth0 and wlan0 into the "physical" namespace:

# ip link set eth0 netns physical# iw phy phy0 set netns name physical

(Note that wireless devices must be moved using iw and by specifying the physical device phy0.)

We now have these interfaces in the "physical" namespace, while having no interfaces in the "init" namespace:

# ip -n physical link1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:002: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether ab:cd:ef:g1:23:45 brd ff:ff:ff:ff:ff:ff3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000 link/ether 01:23:45:67:89:ab brd ff:ff:ff:ff:ff:ff# ip link1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

Now we add a WireGuard interface directly to the "physical" namespace:

# ip -n physical link add wg0 type wireguard

The birthplace namespace of wg0 is now the "physical" namespace, which means the ciphertext UDP sockets will be assigned to devices like eth0 and wlan0. We can now move wg0 into the "init" namespace; it will still remember its birthplace for the sockets, however.

# ip -n physical link set wg0 netns 1

We specify "1" as the "init" namespace, because that's the PID of the first process on the system. Now the "init" namespace has the wg0 device:

# ip link1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:0017: wg0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1423 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1 link/none

We can now configure the physical devices using the ordinary tools, but we launch them inside the "physical" network namespace:

# ip netns exec physical dhcpcd wlan0# ip netns exec physical wpa_supplicant -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant.conf# ip -n physical addr add 192.168.12.52/24 dev eth0

And so forth. Finally, we can configure the wg0 interface like usual, and set it as the default route:

# wg setconf wg0 /etc/wireguard/wg0.conf# ip addr add 10.2.4.5/32 dev wg0# ip link set wg0 up# ip route add default dev wg0

Finished! At this point, all ordinary processes on the system will route their packets through the "init" namespace, which only contains the wg0 interface and the wg0 routes. However, wg0 has its UDP socket living in the "physical" namespace, which means it will send traffic out of eth0 or wlan0. Normal processes won't even be aware of eth0 or wlan0, except dhcpcd and wpa_supplicant, which were spawned inside of the "physical" namespace.

Sometimes, however, you might want to open a webpage or do something quickly using the "physical" namespace. For example, maybe you plan to route all your traffic through WireGuard like usual, but the coffee shop at which you're sitting requires you to authenticate using a website before it will give you a real Internet link. So, you can execute select processes (as your local user) using the "physical" interface:

$ sudo -E ip netns exec physical sudo -E -u \#$(id -u) -g \#$(id -g) chromium

This of course could be made into a nice function for .bashrc:

physexec() { sudo -E ip netns exec physical sudo -E -u \#$(id -u) -g \#$(id -g) "$@"; }

And now you can write the following for opening chromium in the "physical" namespace.

$ physexec chromium

When you're done signing into the coffee shop network, spawn a browser as usual, and surf calmly knowing all your traffic is protected by WireGuard:

$ chromium

Sample Script

The following example script can be saved as /usr/local/bin/wgphys and used for commands like wgphys up, wgphys down, and wgphys exec:

#!/bin/bashset -ex[[ $UID != 0 ]] && exec sudo -E "$(readlink -f "$0")" "$@"up() { killall wpa_supplicant dhcpcd || true ip netns add physical ip -n physical link add wgvpn0 type wireguard ip -n physical link set wgvpn0 netns 1 wg setconf wgvpn0 /etc/wireguard/wgvpn0.conf ip addr add 192.168.4.33/32 dev wgvpn0 ip link set eth0 down ip link set wlan0 down ip link set eth0 netns physical iw phy phy0 set netns name physical ip netns exec physical dhcpcd -b eth0 ip netns exec physical dhcpcd -b wlan0 ip netns exec physical wpa_supplicant -B -c/etc/wpa_supplicant/wpa_supplicant-wlan0.conf -iwlan0 ip link set wgvpn0 up ip route add default dev wgvpn0}down() { killall wpa_supplicant dhcpcd || true ip -n physical link set eth0 down ip -n physical link set wlan0 down ip -n physical link set eth0 netns 1 ip netns exec physical iw phy phy0 set netns 1 ip link del wgvpn0 ip netns del physical dhcpcd -b eth0 dhcpcd -b wlan0 wpa_supplicant -B -c/etc/wpa_supplicant/wpa_supplicant-wlan0.conf -iwlan0}execi() { exec ip netns exec physical sudo -E -u \#${SUDO_UID:-$(id -u)} -g \#${SUDO_GID:-$(id -g)} -- "$@"}command="$1"shiftcase "$command" in up) up "$@" ;; down) down "$@" ;; exec) execi "$@" ;; *) echo "Usage: $0 up|down|exec" >&2; exit 1 ;;esac

A small demo of the above:

Routing & Network Namespaces - WireGuard (3)

Routing & Network Namespaces - WireGuard (2024)

FAQs

Does WireGuard route all traffic? ›

0.0/0 means all trafic gets routed through your wireguard VPN. But you could also only send specific IP's through the VPN. For eg with: 192.168. 1.100/32, 192.168.

How does routing work in WireGuard? ›

At the heart of WireGuard is a concept called Cryptokey Routing, which works by associating public keys with a list of tunnel IP addresses that are allowed inside the tunnel. Each network interface has a private key and a list of peers. Each peer has a public key.

How to check network namespace in Linux? ›

3. Commands to View Namespaces in Linux
  1. 3.1. The lsns Command. The lsns command provides information about all the namespaces in the system. ...
  2. 3.2. Listing the /proc/1/ns Directory.
Mar 18, 2024

Is Tailscale better than WireGuard? ›

Using WireGuard directly offers better performance than using Tailscale. Tailscale does more than WireGuard, so that will always be true. We aim to minimize that gap, and Tailscale generally offers good bandwidth and excellent latency, particularly compared to non-WireGuard VPNs.

How do I route all internet traffic through VPN? ›

Navigate to VPN | Settings and create the VPN policy for the Remote site. You can name the policy as VPN to Central Network. Select the Network tab and under Local Networks you can chose X0 Subnet. Under Remote Networks, select Use this VPN Tunnel as the default route for all Internet traffic.

Which is more secure, WireGuard or OpenVPN? ›

The biggest notable differences between WireGuard and OpenVPN are speed and security. While WireGuard is generally faster, OpenVPN provides heavier security. The differences between these two protocols are also what make up their defining features.

Does WireGuard encrypt all traffic? ›

The WireGuard VPN protocol establishes an encrypted tunnel for all your internet traffic. While most VPN protocols use AES-256 encryption, WireGuard uses newer, ChaCha20 authenticated encryption.

Does WireGuard need TCP or UDP? ›

WireGuard uses only UDP, due to the potential disadvantages of TCP-over-TCP. Tunneling TCP over a TCP-based connection is known as "TCP-over-TCP", and doing so can induce a dramatic loss in transmission performance (a problem known as "TCP meltdown").

Does WireGuard hide IP? ›

As explained above WireGuard does not allocate a dynamic IP address to the VPN user. And, it indefinitely stores user IP addresses on the VPN server until the server reboots. So, there is no anonymity and privacy in WireGuard.

Why use network namespaces? ›

A network namespaces in Linux provide isolation of the system resources associated with networking. They allow to create isolated network environments within one operating system. You can think of them as "boxes" with their own network devices, IP addresses, route tables, ports, firewall rules, etc.

What is the default network namespace? ›

Network namespaces are useful for setting up containers or virtual environments. Each namespace has its own IP addresses, network interfaces, routing tables, and so forth. The default or global namespace is the one in which the host system physical interfaces exist.

What is a namespace example? ›

In an operating system, an example of namespace is a directory. Each name in a directory uniquely identifies one file or subdirectory. As a rule, names in a namespace cannot have more than one meaning; that is, different meanings cannot share the same name in the same namespace.

What makes WireGuard better? ›

WireGuard keeps it simple by operating with fewer than 4,000 lines of code compared to older VPN protocols that typically use thousands more. Fewer lines of code make the protocol's connection, use, and troubleshooting easier, especially for lower-capacity routers and mobile devices.

Should I use IKEv2 or WireGuard? ›

Based on these findings, if you're looking for the fastest secure tunneling protocol, you should go with NordLynx (or WireGuard). The second fastest will be IKEv2, which can confidently hold its own even when connecting to the other side of the world.

Which is better WireGuard or SSH tunneling? ›

WireGuard is cryptographically superior to SSH, attaches at a network layer without fussy interactions with a Unix shell (that then also needs to be accounted for in a security model), has higher performance, is practically bulletproof in terms of keeping connections alive, and gets you direct access to whatever ...

Does VPN redirect all traffic? ›

In the simplest case yes, because it's easier for the user. However, some VPN products allow split tunnelling through which you can specify which traffic should use the VPN while the rest uses the normal connection, or vice-versa.

Is WireGuard full tunnel? ›

WireGuard supports Full Tunnel VPN routing.

Does OpenVPN redirect all traffic? ›

Pushing the redirect-gateway option to clients will cause all IP network traffic originating on client machines to pass through the OpenVPN server. The server will need to be configured to deal with this traffic somehow, such as by NATing it to the internet, or routing it through the server site's HTTP proxy.

Top Articles
Latest Posts
Article information

Author: Frankie Dare

Last Updated:

Views: 5593

Rating: 4.2 / 5 (53 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Frankie Dare

Birthday: 2000-01-27

Address: Suite 313 45115 Caridad Freeway, Port Barabaraville, MS 66713

Phone: +3769542039359

Job: Sales Manager

Hobby: Baton twirling, Stand-up comedy, Leather crafting, Rugby, tabletop games, Jigsaw puzzles, Air sports

Introduction: My name is Frankie Dare, I am a funny, beautiful, proud, fair, pleasant, cheerful, enthusiastic person who loves writing and wants to share my knowledge and understanding with you.