Systemd-networkd: How can I prepend a static nameserver entry to DHCP-discovered nameservers?

I'm using systemd 213 on Arch Linux, and systemd-networkd/resolved with DHCP to connect to the internet. I'm also running a caching DNS server on 127.0.0.1. I'd like to make this server the first DNS server in the list, but I'd also like to use the nameservers discovered by systemd-resolved. Using a static resolv.conf isn't really possible, because I connect to networks with different DNS settings.

I know I can set fallback DNS servers in /etc/systemd/resolved.conf, but is there a way with systemd-networkd to prepend my local DNS server to those discovered by DHCP?


Edit: What I've tried so far

  • Adding a manual DNS entry in the .network file results in that entry being appended instead of prepended:

    # This file is managed by systemd-resolved(8). Do not edit.
    #
    # Third party programs must not access this file directly, but
    # only through the symlink at /etc/resolv.conf. To manage
    # resolv.conf(5) in a different way, replace the symlink by a
    # static file or a different symlink.
    
    nameserver 141.48.3.51
    nameserver 141.48.3.17
    nameserver 141.48.3.3
    # Too many DNS servers configured, the following entries may be ignored
    nameserver 127.0.0.1
    
  • If I add UseDNS=true in the [DHCPv4] section as well, as described in the systemd.network(5), manpage, the nameservers discovered by DHCP are ignored and only the static DNS entry is used, which is not what I want either:

    # This file is managed by systemd-resolved(8). Do not edit.
    #
    # Third party programs must not access this file directly, but
    # only through the symlink at /etc/resolv.conf. To manage
    # resolv.conf(5) in a different way, replace the symlink by a
    # static file or a different symlink.
    
    nameserver 127.0.0.1
    
  • Using the in_addr representation for the DNS address just appends my nameserver, just like using the normal representation.


Have you tried adding these two lines:

  [Network]
  DNS=127.0.0.1

to one of the files /etc/systemd/network/*.network? For instance, for a dhcp client, modify /etc/systemd/network/80-dhcp.network to contain the lines:

  [Match]
  Name=en*

  [Network]
  DHCP=yes
  DNS=127.0.0.1

EDIT:

Have you tried the in_addr representation? Try substituting 127.0.0.1 with 16777343.


The trick seems to be that your config file in /etc/systemd/network must lexically sort earlier than the default configs in /run/systemd/network which are prefixed with 10-. Note that if you override the default configuration you must also enable DHCP on the interface otherwise the interface will come up without DHCP configured.

Here's an example config file that I placed at /etc/system/network/1-test.network:

[Match]
Name=ens5

[Network]
DHCP=ipv4
DNS=8.8.8.8

[DHCP]
UseDNS=false

To apply these settings run systemctl restart systemd-networkd. This doesn't appear to bring down the interface, just re-configure it. You can then use networkctl status ens5 to validate that the settings were applied.

I validated this at least works on Ubuntu 18.04 (bionic).