Integrating OpenVPN Pushed DNS with systemd-resolved: A Complete Implementation Guide


2 views

When connecting through OpenVPN, servers often push DNS configurations that need integration with the local resolver. Traditional methods using resolvconf scripts don't work well with systemd-resolved, which manages DNS through its own API rather than direct /etc/resolv.conf modifications.

systemd-resolved maintains DNS configuration in three key locations:

/run/systemd/resolve/resolv.conf
/etc/resolv.conf (symlink)
DBus interface for dynamic configuration

Create a custom script that interfaces with systemd-resolved's DBus API:

#!/bin/bash
# /etc/openvpn/update-systemd-resolved

case $script_type in
  up)
    for optionname in ${!foreign_option_*} ; do
      option="${!optionname}"
      if [[ "$option" =~ ^dhcp-option\ DNS\ (.*)$ ]] ; then
        DNS="${BASH_REMATCH[1]}"
        busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 \
          org.freedesktop.resolve1.Manager SetLinkDNS ia(iay) \
          $dev 1 2 4 ${DNS//./ }
      fi
    done
    ;;
  down)
    busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 \
      org.freedesktop.resolve1.Manager RevertLink i $dev
    ;;
esac

1. Save the script to /etc/openvpn/update-systemd-resolved
2. Make it executable:
chmod +x /etc/openvpn/update-systemd-resolved
3. Add to OpenVPN client config:
script-security 2
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved

Check active DNS configuration after connection:
resolvectl status
Look for your VPN interface in the output with the pushed DNS servers listed.

For split-DNS scenarios where only certain domains should use VPN DNS:

# Add to the 'up' case in the script
if [[ "$option" =~ ^dhcp-option\ DOMAIN\ (.*)$ ]] ; then
  DOMAIN="${BASH_REMATCH[1]}"
  busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 \
    org.freedesktop.resolve1.Manager SetLinkDomains a(sb) \
    $dev 1 "$DOMAIN" true
fi

If DNS isn't working:
- Verify script is executable and called properly in OpenVPN log
- Check DBus is running: systemctl status dbus
- Ensure systemd-resolved is active: systemctl status systemd-resolved


When establishing an OpenVPN connection, DNS servers are often pushed from the VPN server to enable proper name resolution for internal resources. Traditionally, this was handled by scripts like openvpn-update-resolv-conf which modified /etc/resolv.conf directly. However, with modern systems using systemd-resolved, we need a different approach.

systemd-resolved manages DNS configuration through its own database at /run/systemd/resolve/resolv.conf. The key components involved are:

  • DNS server list management
  • Per-link DNS configuration
  • DNSSEC validation

Here's how to properly configure OpenVPN to work with systemd-resolved:

1. Create an OpenVPN Up/Down Script

#!/bin/bash
# /etc/openvpn/update-systemd-resolved

case $script_type in
    up)
        for optionname in ${!foreign_option_*}; do
            option="${!optionname}"
            if [[ "$option" =~ ^dhcp-option\ DNS ]]; then
                DNS=${option##dhcp-option DNS }
                resolvectl dns "$dev" "$DNS"
                resolvectl domain "$dev" "~${DNS%% *}"
            fi
        done
        ;;
    down)
        resolvectl revert "$dev"
        ;;
esac

2. Configure OpenVPN Client

Add these lines to your OpenVPN client configuration:

script-security 2
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved
down-pre

After connecting to your VPN, check the active DNS configuration:

resolvectl status

You should see your VPN interface listed with the pushed DNS servers.

For more complex setups, consider these additional parameters:

# Set DNS priority (lower number = higher priority)
resolvectl dns "$dev" "$DNS" --set-dns-priority=10

# Configure search domains
resolvectl domain "$dev" "~internal.example.com" "~vpn.example.com"

# Enable DNSSEC for the VPN connection
resolvectl dnsssec "$dev" yes
  • DNS leaks: Verify with dig +short myip.opendns.com @resolver1.opendns.com
  • Connection delays: Adjust DNS priority to prevent timeouts
  • Domain resolution failures: Check search domain configuration

If using NetworkManager with OpenVPN, you can configure DNS handling directly:

[ipv4]
dns=192.168.1.1;
dns-search=internal.example.com;
ignore-auto-dns=true