Overview

I’m running a RHEL system (in a VM on a MAC to be accurate) from where i manage a couple of systems residing behind a VPN connection. These systems have their own little network with their own DNS service.
I want to tell my RHEL system to use the specific DNS servers for the relevant domains while leaving everything else just working as before.

Problem Statement

If the VPN connection is set up properly, it should pass along the relevant DNS servers and should tell your networking client how to change DNS configuration, so that everything just works. But as it is not, i simply want to change the resolver configuration. To achieve this we need to get our heaad around 2 topics:

  • Typically in /etc/resolv.conf dns resolvers know a couple of DNS servers, all delivering the same answers to any question they get. They do not differentiate on the domain they are asking for or anything as the assumption is, that the servers will figure out any Name within the domain name tree.
  • RHEL systems use NetworkManager to configure networking and name resolution. And this is for making networking just work, even if the surrounding (e.g. different wifi, cabled connection, VPN active) changes. It is very likely that your resolver configuration will be overwritten by NetworkManager.

I want to keep the system as much as possible unaltered and running the same way, but with the addition of these specific domains being resolved by a specific DNS server.

Options

Looking at some options to move forward, i evaluated the following:

Switch of NetworkManager

This would radically solve the persistence challenge, but it would need additional thoughts to have a specific name server for a specific domain (yet).
But i’d say this does not relate to the idea to leave the system untouched and will most likely break a lot of automatisms around networking, which then need to be set up manually (dhcp client setup, etc.).

Make NetworkManager not manage resolver configuration

This would also solve the persistence challenge, but it would also need additional thoughts to have a specific name server for a specific domain (yet).
This is a nice compromise. The downside would still be that automatic dns configuration, e.g. via DHCP, are not taken into account and will need manual intervention.
How to ensure NetworkManager will not configure your resolver configuration is described here [1] for RHEL 8. Other RHEL versions should be similar.

Use systemd-resolvd

This would most likely solve both problems at the same time. Red Hat’s RHEL documentation provides a way to use systemd-resolvd [2] to “Using different DNS servers for different domains”, as the headline claims. The documentation explains how this demaon is enabled and from what i read it is nicely integrated into NetworkManager. Unfortunately i did not find additional documentation on where to put / how to configure my specific domain related nameserver. Maybe i’m missing the obvious, but i did not follow up on this either.

Use unbound

Unbound is a caching only, forwarding only – nameserver capable to do exactly what is needed here. I believe unbound is more targeted to server a local network instead of just the host itself which it runs on. Unbound is configured and managed as a server system.

Use dnsmasq managed by NetworkManager

For similar challenges dnsmasq is often used. It is manageable by NetworkManager and is capable to address different name servers depending on the domain in question. The beauty of this path is, that dsnmasq extends the network configuration of the host given. There is no additional networking server to be managed, as it is integrated into NetworkManager, which takes care of the networking configuration and name resolution configuration anyway. The “forwarder” configuration provided by a dhcp service will nicely be used by dnsmasq. So this is the preferable choice.

What i did

We have a 2 step approach. First we enable dnsmasq and second we add our domain specific configuration to it.

Enable dnsmasq

I followed the second approach in [3], headlined “Configure dnsmasq to run under control of NetworkManager”. This enables dnsmasq via NetworkManager like this:

  • created dns.conf file:
[root@rhel9msi ~]# cat  /etc/NetworkManager/conf.d/dns.conf
[main]
dns=dnsmasq
  • restart Network Manager
[root@rhel9msi ~]# systemctl restart NetworkManager
  • check outcome
[root@rhel9msi ~]# systemctl status NetworkManager
● NetworkManager.service - Network Manager
     Loaded: loaded (/usr/lib/systemd/system/NetworkManager.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-04-25 11:40:43 CEST; 2h 33min ago
       Docs: man:NetworkManager(8)
   Main PID: 72540 (NetworkManager)
      Tasks: 4 (limit: 74497)
     Memory: 6.7M
        CPU: 1.963s
     CGroup: /system.slice/NetworkManager.service
             ├─72540 /usr/sbin/NetworkManager --no-daemon
             └─72621 /usr/sbin/dnsmasq --no-resolv --keep-in-foreground --no-hosts --bind-interfaces --pid-file=/run/NetworkManager/dnsmasq.pid --listen-address=127>

Apr 25 11:40:56 rhel9msi.example.com dnsmasq[72621]: cleared cache
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.0853] device (enp0s3): state change: ip-check -> secondaries (reason 'none', sys-ifa>
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.1199] device (enp0s3): state change: secondaries -> activated (reason 'none', sys-if>
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.1223] manager: NetworkManager state is now CONNECTED_SITE
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.1250] device (enp0s3): Activation: successful, device activated.
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.1267] manager: NetworkManager state is now CONNECTED_GLOBAL
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.2427] device (enp0s8): state change: ip-check -> secondaries (reason 'none', sys-ifa>
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.2740] device (enp0s8): state change: secondaries -> activated (reason 'none', sys-if>
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.3970] device (enp0s8): Activation: successful, device activated.
Apr 25 11:40:57 rhel9msi.example.com NetworkManager[72540]: <info>  [1682415657.4382] manager: startup complete
[mschreie@rhel9msi ~]$ ps -ef | grep dns
dnsmasq 967 889 0 Apr27 ? 00:00:02 /usr/sbin/dnsmasq --no-resolv --keep-in-foreground --no-hosts --bind-interfaces --pid-file=/run/NetworkManager/dnsmasq.pid --listen-address=127.0.0.1 --cache-size=400 --clear-on-reload --conf-file=/dev/null --proxy-dnssec --enable-dbus=org.freedesktop.NetworkManager.dnsmasq --conf-dir=/etc/NetworkManager/dnsmasq.d
mschreie 33545 5942 0 13:08 pts/2 00:00:00 grep --color=auto dns
[mschreie@rhel9msi ~]$ cat /etc/resolv.conf
# Generated by NetworkManager
search hpintelco.org example.com
nameserver 127.0.0.1
options edns0 trust-ad

Add specific domain configuration

The systemctl command just shows that NetworkManager is up and running. More interesting the fact that now there is a dnsmasq process as well. A third interesting thing: The resolver configuration does point to dnsmasq on localhost.

[mschreie@rhel9msi ~]$ cat /etc/NetworkManager/dnsmasq.d/mydomain.conf
server=/my.specific.domain.com/10.1.2.4
server=/2.1.10.in-addr.arpa/10.1.2.4
server=/3.1.10.in-addr.arpa/10.1.2.4

Conclusion

We found an easy way to tell the local system to ask a specific dns server for a specific dns domain search. And do the same for the reverse domains. This solution lets everything else untouched, so that NetworkManager can still alter networking and name resolution according to the current environment and the available connections. This solution works well for a personal laptop being connected in different offices or locations with different network setups.

Links

[1] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/manually-configuring-the-etc-resolv-conf-file_configuring-and-managing-networking

[2] https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/configuring_and_managing_networking/using-different-dns-servers-for-different-domains_configuring-and-managing-networking

Within the help of the ps command in our fist step we found the dnsmaq process with all it’s parameters. So i created a file with my forward and backward domains pointing to a specific server:

[3] https://access.redhat.com/solutions/2189401