3

I'm trying to route all traffic from a specific Docker Network (10.222.111.0/24) via an wg0 systemd network interface, config:

/etc/systemd/network/30-wg0.netdev

[NetDev]
Name = wg0
Kind = wireguard
Description = Wireguard

[WireGuard]
PrivateKey = XXXX

[WireGuardPeer]
PublicKey = XXXX
AllowedIPs = 10.222.111.0/24
Endpoint = XXXX:51820
PersistentKeepalive = 25

/etc/systemd/network/30-wg0.network

[Match]
Name=wg0

[Network]
Address = 10.0.3.227/19
DNS = X.X.X.X

[Route]
Gateway = 10.0.3.227
Destination = 10.222.111.0/24

Now I can see the interface comeing up, and the correct route in the routing table

# ip route show
...
10.222.111.0/24 via 10.0.3.227 dev wg0 proto static
...

The interface is up and running

# networkctl status wg0
● 251: wg0
       Link File: /lib/systemd/network/99-default.link
    Network File: /etc/systemd/network/30-wg0.network
            Type: none
           State: routable (configured)
         Address: 10.0.3.227
         DNS: X.X.X.X

However an attempt at testing this fails:

# curl --interface wg0 https://ifconfig.me 
# public ip of remote server

# docker network create vpn --subnet 10.222.111.0/24
# docker run --rm --dns X.X.X.X --network vpn --ip 10.222.111.110 appropriate/curl -s https://ifconfig.me
# no output

Output of tcpdump when running the docker run command:

# tcpdump -nn -i wg0 host ifconfig.me
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wg0, link-type RAW (Raw IP), capture size 262144 bytes
08:36:16.127461 IP 10.0.3.227.33182 > 216.239.38.21.443: Flags [S], seq 1530371569, win 27600, options [mss 1380,sackOK,TS val 3454949182 ecr 0,nop,wscale 7], length 0
08:36:17.152770 IP 10.0.3.227.33182 > 216.239.38.21.443: Flags [S], seq 1530371569, win 27600, options [mss 1380,sackOK,TS val 3454950207 ecr 0,nop,wscale 7], length 0
08:36:17.152830 IP 10.0.3.227.33182 > 216.239.38.21.443: Flags [S], seq 1530371569, win 27600, options [mss 1380,sackOK,TS val 3454950207 ecr 0,nop,wscale 7], length 0
08:36:17.153083 IP 10.0.3.227.48686 > 216.239.36.21.443: Flags [S], seq 1139719299, win 27600, options [mss 1380,sackOK,TS val 3564689990 ecr 0,nop,wscale 7], length 0
08:36:18.176752 IP 10.0.3.227.48686 > 216.239.36.21.443: Flags [S], seq 1139719299, win 27600, options [mss 1380,sackOK,TS val 3564691014 ecr 0,nop,wscale 7], length 0
08:36:18.176798 IP 10.0.3.227.48686 > 216.239.36.21.443: Flags [S], seq 1139719299, win 27600, options [mss 1380,sackOK,TS val 3564691014 ecr 0,nop,wscale 7], length 0
08:36:18.176891 IP 10.0.3.227.59316 > 216.239.34.21.443: Flags [S], seq 3848190866, win 27600, options [mss 1380,sackOK,TS val 3672200215 ecr 0,nop,wscale 7], length 0
08:36:19.200840 IP 10.0.3.227.59316 > 216.239.34.21.443: Flags [S], seq 3848190866, win 27600, options [mss 1380,sackOK,TS val 3672201239 ecr 0,nop,wscale 7], length 0
08:36:19.200938 IP 10.0.3.227.59316 > 216.239.34.21.443: Flags [S], seq 3848190866, win 27600, options [mss 1380,sackOK,TS val 3672201239 ecr 0,nop,wscale 7], length 0
08:36:19.201089 IP 10.0.3.227.39842 > 216.239.32.21.443: Flags [S], seq 4281397520, win 27600, options [mss 1380,sackOK,TS val 1995655620 ecr 0,nop,wscale 7], length 0
08:36:20.224781 IP 10.0.3.227.39842 > 216.239.32.21.443: Flags [S], seq 4281397520, win 27600, options [mss 1380,sackOK,TS val 1995656643 ecr 0,nop,wscale 7], length 0
08:36:20.224894 IP 10.0.3.227.39842 > 216.239.32.21.443: Flags [S], seq 4281397520, win 27600, options [mss 1380,sackOK,TS val 1995656643 ecr 0,nop,wscale 7], length 0
^C
12 packets captured
12 packets received by filter
0 packets dropped by kernel

I'm sure I've missed something, however I fail to see what. Partly based on https://nbsoftsolutions.com/blog/leaning-on-algo-to-route-docker-traffic-through-wireguard

4
  • 2
    What's on the other end of the wireguard interface? One way to debug this is to run several bashs in the container, use them to tcpdump both wg0 and the container interface (and maybe the host interface, too, for good measure), do the same on the other end of the wireguard interface, then ping (or curl, if you insist) and see how far the packets get and where they get dropped. Then you have narrowed down the problem.
    – dirkt
    Jun 30, 2019 at 6:36
  • 2
    I'm not in control of the remote server, which makes it a bit difficult to debug. However on my laptop where I don't do any specific routing (everything goes via wg0 to the same remote service) everything works fine, so I'm sure its a config issue on this server. I attached the output of tcpdump to main post Jun 30, 2019 at 6:40
  • 2
    Ok, so you are seeing packets going into wg0, but no packets coming out. This doesn't tell us anything new, which is why you need tcpdump on the other interfaces (container, host) too. For example, if you see packets going to the other wireguard interface on the host interface, but no packets coming back, the problem is somewhere in the wireguard connection. If there are no outgoing packets to the other end on the host, the problem is with docker routing. Etc.
    – dirkt
    Jun 30, 2019 at 6:48
  • 2
    Thanks @dirkt. I missed a config option on the wg0 interface (main post updated), so now the curl --interface wg0 test works (tcpdump confirms), however from within the docker it fails. I'm guessing a missing route rule? Jun 30, 2019 at 7:10

1 Answer 1

3

I faced the same problem, this is how I got it to work:

Your main mistake was how you used AllowedIPs in the net device. AllowedIPs specifies the allowed target IPs, and since you probably want to tunnel traffic to all IPs, you should specify 0.0.0.0/0.

The Destination line in the [Route] section and the resulting route (10.222.111.0/24 via 10.0.3.227 dev wg0 proto static) is also the wrong way around: This routes traffic targeting 10.222.111.0/24 to the WireGuard interface instead of traffic originating from that subnet.

To filter by source, so that all traffic from the docker subnet goes through the VPN, you can use a [RoutingPolicyRule] (the equivalent of ip rule) and a [Route] (the equivalent of ip route) section in the network file, so your networkd files look like this:

etc/systemd/network/30-wg0.netdev:

[NetDev]
Name = wg0
Kind = wireguard
Description = Wireguard

[WireGuard]
PrivateKey = XXXX

[WireGuardPeer]
PublicKey = XXXX
AllowedIPs = 0.0.0.0/0
Endpoint = XXXX:51820
PersistentKeepalive = 25

/etc/systemd/network/30-wg0.network:

[Match]
Name=wg0

[Network]
Address = 10.0.3.227/19
DNS = X.X.X.X

[RoutingPolicyRule]
From = 10.222.111.0/24
# Or any other unused table number
Table = 242

[Route]
# The address of the interface, same as in Address line
Gateway = 10.0.3.227
# Same table number as above
Table = 242

With that config both curl --interface wg0 and

# docker network create vpn --subnet 10.222.111.0/24
# docker run --rm --dns X.X.X.X --network vpn appropriate/curl -s https://ifconfig.me

should work fine (note I removed the --ip option in docker run as it's not necessary).

I actually wrote a blog article about my solution with detailed instructions, you can take a look if you want, it might help: https://www.eisfunke.com/article/docker-wireguard-systemd.html.

Hope that helps!

2
  • How would/could this work when Network->Address and Route->Gateway is not know beforehand? Eg from an VPN provider Apr 11, 2020 at 19:33
  • @JoelKåberg Well, you wouldn't. WireGuard needs an IP address. A VPN provider needs to give you an IP address to use for the connection beforehand. E.g. my VPN provider Mullvad provides wg-quick config files for connecting including an IP (and also the keys etc.) that can also be used with systemd-networkd for WireGuard, which is what I do on my machine.
    – Eisfunke
    Apr 12, 2020 at 20:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .