Table of Contents
OpenVPN DNS update
1. Using systemd-resolve
1.1 Theory
1.2 Manual configuration
Prerequisites
First check if you have systemd-resolved installed and running:
systemctl status systemd-resolved Check if you have the resolvectl too:
resolvectl An alternative is to use systemd-resolve:
systemd-resolve --status
Check if have the resolve mechanism enabled in nssswitch.conf:
cat /etc/nsswitch.conf | grep ^hosts: | grep resolve
Install the needed libraries. For example on Debian or Ubuntu AMD64 systems:
dpkg -l | grep libnss-resolve
Note: I'm installing both the 64 bit and 32 bit libraries. If you do not install the 32 bit libraries, proper DNS resolution might fail for 32 programs.
Symlink /etc/resolv.conf is a symlink to /var/run/netconfig/resolv.conf autogenerated by netconfig!
Call to force adjusting of /etc/resolv.conf.
netconfig update -f
Summary
If you are using a Linux system with systemd-resolved, a quick fix is something like this (your need to adjust these values):
# Configure internal corporate domain name resolvers: resolvectl dns tun0 192.0.2.53 192.0.2.54 # Only use the internal corporate resolvers for domain names under these: resolvectl domain tun0 "~foo.example.com" "~bar.example.com" # Not super nice, but might be needed: resolvectl dnssec tun0 off
If you don't have the resolvectl commands, you might use instead:
systemd-resolve -i tun0 \ --set-dns=192.0.2.53 --set-dns=192.0.2.54 \ --set-domain=foo.example.com --set-domain=bar.example.com \ --set-dnssec=off # <- Not super nice, but might be needed.
Details
Configure DNS resolution
If all these prerequisites are satisfied, you can configure the DNS resolution with something like:
resolvectl dns tun0 192.0.2.53 192.0.2.54 resolvectl domain tun0 "~foo.example.com" "~bar.example.com"
Alternatively, if you don't have resolvectl:
systemd-resolve -i tun0 \ --set-dns=192.0.2.53 --set-dns=192.0.2.54 \ --set-domain=~foo.example.com --set-domain=~bar.example.com
This configures systemd-resolved to use the corporate internal resolvers 192.0.2.53 and 192.0.2.54 for resolving all domain names under foo.example.com and bar.example.com (eg. some-service.foo.example.com). tun0 is network interface of the VPN. You have to adjust these parameters (IP address, domain names).
Note: the ~ in front of a domain prevents the domain to be added to the search list (i.e. trying to resolve the test host name will not search test.foo.example.com if a ~ was used in front of foo.example.com).
You can check your system-resolved configuration with:
resolvectl
If you don't have resolvectl:
systemd-resolve --status
You can now test domain name resolution (assuming some-service.foo.example.com actually exists):
resolvectl query some-service.foo.example.com
If you don't have resolvectl:
systemd-resolve some-service.foo.example.com
If this works, you should have:
some-service.foo.example.com: 192.0.2.22 -- link: tun0 -- Information acquired via protocol DNS in 1.7ms. -- Data is authenticated: no
In my case, this failed because of:
some-service.foo.example.com: resolve call failed: DNSSEC validation failed: failed-auxiliary A quick/dirty fix is to disabled DNSSEC:
resolvectl dnssec tun0 off
If you don't have resolvectl:
systemd-resolve -i tun0 \ --set-dns=192.0.2.53 --set-dns=192.0.2.54 \ --set-domain=foo.example.com --set-domain=bar.example.com \ --set-dnssec=off
Hooking with OpenVPN (CLI)
If you are using OpenVPN directly from the CLI (not through Network Manager), you can automate this with the –up options.
For example:
openvpn --config client.ovpn --script-security 2 --up ./manual-config
where ./manual-config is a shell script such as:
#!/bin/sh set -e resolvectl dns $dev 192.0.2.53 192.0.2.54 resolvectl domain $dev "~foo.example.com" "~bar.example.com" resolvectl dnssec $dev off or #!/bin/sh systemd-resolve -i $dev \ --set-dns=192.0.2.53 --set-dns=192.0.2.54 \ --set-domain=foo.example.com --set-domain=bar.example.com \ --set-dnssec=off # <- Not super nice, but might be needed. OpenVPN sets the dev environment variable to the name of the VPN TUN/TAP (i.e. virtual) network device (eg. tun0) when calling the hooks.
Don't forget to make this script executable.
Using update-systemd-resolved An alternative is to use the update-systemd-resolved script (on Debian and Ubuntu it is in the openvpn-systemd-resolved package):
openvpn \ --config client.ovpn \ --up /etc/openvpn/update-systemd-resolved \ --down /etc/openvpn/update-systemd-resolved \ --down-pre \
This automatically pulls configuration advertised by the VPN server:
resolver to used; domain names; whether to disable DNSSEC. If this fails, the previous section might help you pinpoint to the problem:
check the configuration (resolvectl); test internal/external names resolution (resolvectl query some-service.foo.example.com)
disable DNSSEC if needed (resolvectl dnssec tun0 off).