Wg-quick and DNS

,

Hello all,
I don’t know how many of you are using wireguard on a Linux client, but I found an interested problem as it relates to DNS and was wondering if anyone had any solutions that they could point me to that would be better than my hacky workaround that I have put together.

The Problem

My wg-easy client config file looks like so:

[Interface]
PrivateKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
Address = 10.8.0.2/24
DNS = 10.63.0.222

[Peer]
PublicKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
PresharedKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 0
Endpoint = wg.mydomain.com:51820

As you can see, it sets the DNS server to 10.63.0.222 which works fine genarally as my /etc/resolv.conf file gets overwritten to:

# Generated by resolvconf
nameserver 10.63.0.222

… which results in dig commands coming back from my internal DNS server.

However, I found that as soon as I would run any docker compose up commands, my /etc/resolv.conf file was getting reset back to using the stub resolver at 127.0.0.53, which resulted in my computer using the DNS server handed down to me from the DHCP server at this remote location (not ideal).

The Workaround

As a hacky workaround, I found that I could run some commands to manually reconfigure my systemd resolver to set the IP address of my internal server. I do this like so:

sudo echo "[Resolve]" | sudo tee /etc/systemd/resolved.conf.d/wireguard.conf
sudo echo "DNS=10.63.0.222" | sudo tee -a /etc/systemd/resolved.conf.d/wireguard.conf
sudo echo "Domains=~." | sudo tee -a /etc/systemd/resolved.conf.d/wireguard.conf
sudo echo "" | sudo tee -a /etc/systemd/resolved.conf.d/wireguard.conf

sudo systemctl daemon-reload
sudo systemctl restart systemd-resolved

This must be done after having successfully made the VPN connection.

When I have finished with the VPN connection, I need to reset things back to how they were by removing the config file, and restarting the resolver service like so:

# change DNS back to how it used to be.
sudo rm /etc/systemd/resolved.conf.d/wireguard.conf
sudo systemctl daemon-reload
sudo systemctl restart systemd-resolved

To make life easy, I put the whole lot in a single script, that makes the connection, updates the DNS, and ties up the console until I run ctrl-c, which will then shutdown the connection and return DNS to how it was before. I do this in a tmux session (through byobu).

#!/bin/bash
wg-quick up /path/to/vpns/connection-name/client.conf

# configure systemd to use the wireguard connected DNS server.
sudo echo "[Resolve]" | sudo tee /etc/systemd/resolved.conf.d/wireguard.conf
sudo echo "DNS=xxx.xxx.xxx.xxx" | sudo tee -a /etc/systemd/resolved.conf.d/wireguard.conf
sudo echo "Domains=~." | sudo tee -a /etc/systemd/resolved.conf.d/wireguard.conf
sudo echo "" | sudo tee -a /etc/systemd/resolved.conf.d/wireguard.conf

sudo systemctl daemon-reload
sudo systemctl restart systemd-resolved

# Tie up the console with stats about the connection, until I press ctrl-c
watch -n 1 sudo wg show

# We get here after pressing ctrl-c, shutdown the VPN connection.
wg-quick down /path/to/vpns/connection-name/client.conf

# change DNS back to how it used to be.
sudo rm /etc/systemd/resolved.conf.d/wireguard.conf
sudo systemctl daemon-reload
sudo systemctl restart systemd-resolved

Question

Is there some way to configure wg-quick to perform the systemd DNS configuration work, which would feel less hacky? It would be better from the point of view of having one DNS server IP set just once in the wg-quick client configuration, rather than me having to duplicate it in my workaround script as well.

I would rather look at why docker is overwriting resolv.conf. In my opinion it shouldn’t.

Maybe you have this issue?

This is a systemd-resolved problem (I just remembered how many headaches I had with this on Fedora about 5 years ago, when trying to set a wg VPN on linux). I think there’s a way to disable that, but I don’t remember how. If you don’t want to do that, I can think of 2 options:

  • the extreme way is to run a router (it can be a raspberry pi 3 for all it matters, although something with lower power consumption is better, if you can live without the performance, or you might want something better, like a lattepanda if you want to squeeze all the wifi performance in a small form-factor) and run wg there, then have your device wired to it (I assume it’s a laptop) - that will prevent any kind of leaks if you set your firewall right (block all incoming on eth0 from going to wlan0 and allow all incoming on eth0 to go on wg0)
  • the less extreme option is to work around that, by running your wireguard server automate the change of the systemd-resolved IP address, using “PostUp =” and “PostDown =” - the 1st is when the interface gets set up, the 2nd is when you stop the wg tunnel
PostUp = printf "[Resolve]\nDNS=10.63.0.222\nDomains=~.\n" | tee /etc/systemd/resolved.conf.d/wireguard.conf && systemctl daemon-reload && systemctl restart systemd-resolved

IDK how PostDown would look in reverse, maybe just deleting the file and reconfiguring resolved?

PostDown = rm -f /etc/systemd/resolved.conf.d/wireguard.conf && systemctl daemon-reload && systemctl restart systemd-resolved

The PostUp and PostDown lines should go under the [Interface] part of the wg conf. Of course, if you don’t want to be dependent on the commands running successfully (&&), you can use semicolon (;), just like in any shell, but you gotta put everything on a single line.

For low-power VPN setups in a fairly small form-factor and running a webGUI, you might want to grab a thinkpenguin tpe-r1300. It’s only going to land you 100 Mbps on the wired lan and wifi 5 (n) on wlan (which is perfectly fine on-the-go). If you want something beefier and “no frills” when it comes to config, look for a router that runs openwrt. It’s going to be more expensive than a simple SBC and it’s going to require more power (so you’d need a dedicated large power bank for it, I like my anker 737, it can even power laptops, so it should be capable of powering a 12v access point for a couple of hours, if you get the right type-c to 12v barrel jack plug and adapt it to the barrel size for your openwrt wireless WAN router).

2 Likes

Thanks for that, putting the DNS stuff inside the wireguard config (in the interface section), would at least mean I had just one place where the DNS was set, and means if the IP changes, I’m more likely to replace all instances that I need to update. I’ll have to give that a try.