0

What's the most reliable configuration to have a fixed list of internal domains always resolved through an internal nameserver, even if it's unreachable because the VPN is down, while still using the default nameserver for everything else?

The connection is established by NetworkManager after selecting the appropriate interface or network in KDE (or another desktop environment).

This question is specifically about defining a static list of VPN domains because:

  • Suppose there are three internal domains, which are known only to the internal nameserver within the VPN, two of which are automatically added to /etc/resolv.conf as "search" domains whenever the VPN connection is established, along with the internal nameserver, which is prepended to that file, if the VPN client is configured to do so.
  • Suppose the internal domains of the main VPN are ".int", ".org", and ".test.net" and the first two would be added as search domains if the client was configured to change the resolv.conf file.
  • If the VPN client changes /etc/resolv.conf after establishing the connection, all DNS requests are sent to the internal nameserver, which should handle only the three internal domains but can't handle some other domains.
  • Whenever the VPN connection is lost, the VPN client would automatically reset the resolv.conf file, leaving only the standard nameserver assigned by DHCP, added by NetworkManager. So whenever the VPN is down, internal DNS requests are leaked; they're sent to the standard nameserver, which either doesn't know about them or resolves them to different, external IPs.
  • Whenever a connection is established in KDE, the nameserver assigned by DHCP is written to the file. NetworkManager takes care of that, and if it was a link to a file containing only nameserver localhost, it would probably have to write the received nameserver IP address to some uplink.conf file, which would be used by the resolver.
  • It wouldn't be necessary to make any additional changes to the resolv.conf file if it was a symlink to a file containing only nameserver localhost and if the local resolver would always know how to forward queries depending on the domain.
  • The IP address of the internal nameserver is static and so is the list of internal domains: DNS queries for these internal domains should only ever be sent to the internal nameserver, no exceptions.
  • DNS queries to other domains should be handled by the standard nameserver, as usual. Similar questions have been solved by manually configuring a nameserver but in this case, the system should use the one assigned by DHCP.
  • A quick attempt with dnsmasq failed. After configuring server=/int/10.1.1.1 etc., it still sent queries for xxx.int to the standard nameserver instead. The log file showed both using nameserver 10.1.1.1#53 for domain int and using nameserver 192.168.1.1#53 for domain int, where 192.168.1.1 was the standard nameserver assigned by DHCP (so DNS queries were leaking). A solution with systemd-resolved is preferred but config examples for other resolvers are welcome as well.
  • The focus of the question is the configuration of a local resolver like systemd-resolved, regardless of the state of the VPN connection or if a second VPN connection is currently active.
  • This question is not about one specific distribution; it's for any distribution that uses systemd and has KDE. For example, Fedora 33 uses systemd-resolved by default, so a config example for it would be great.
  • Standard tools like dig, host, nslookup or ping must work (i.e., not send queries to the wrong nameserver).

There are similar questions on this site, usually without the requirement of not leaking queries, as well as on other sites. For example, an article on gnome.org seems to address the split DNS question under "My Corporate VPN is Missing a Routing Domain, What Should I Do?", but it expects all internal domains to be set by the VPN client and states:

...  Sadly, not all VPNs actually do this properly, since it doesn’t matter for traditional non-split DNS.  Worse, there is no graphical configuration in GNOME System Settings to fix this.  There really should be.  But for now, you’ll have to use nmcli ...

Having to use such a command does not seem like a reliable configuration. And DNS queries shouldn't be leaked if the connection is lost for a moment. The article continues with:

Hopefully you never have to mess with this.

What if you do? The scenario shouldn't be too uncommon; there must be at least one standard solution.


For the record, this dnsmasq config was tried but it doesn't fulfill the requirement of defaulting to the standard nameserver provided by DHCP:

/etc/dnsmasq.d/dns-int.conf:

no-resolv
server=/int/10.1.1.1
server=/org/10.1.1.1
server=/test.net/10.1.1.1
server=/google.com/8.8.8.8 # example
server=9.9.9.9 # not wanted
log-queries

In /etc/NetworkManager/NetworkManager.conf, under section [main]:

dns=dnsmasq

Add a symlink to the config directory used by NetworkManager pointing to the config file that would be used when starting dnsmasq directly using systemctl start dnsmasq:

`/etc/NetworkManager/dnsmasq.d/dns-int.conf` -> `/etc/dnsmasq.d/dns-int.conf`

However, as explained above, this configuration is not completely correct.

1
  • @faran: (1) You missed the abbreviations in the title.  (2) Even if something is ''obviously wrong'', please make sure that you are changing it to what it should be, not just something different.  You changed "how how" to "how", apparently believing that it was simply a repeated-word typo.  But I believe that the sentence didn't make sense after your edit, and that "how how" was a typo for "know how". – G-Man Says 'Reinstate Monica' May 4 at 17:21
0

This question is mainly about systemd-resolved, but I thought it might be valuable to describe my attempt with dnsmasq in a separate answer. I'm downvoting mine so that other answers show up first and also because it's unclear why it didn't work initially. Edit: Seems like I can't downvote my own post. Maybe someone else can do that.

dnsmasq

First of all, it should not be necessary to specify an "uplink" config file with the list of default nameservers because NetworkManager sends that list to dnsmasq through dbus. But I guess if that didn't work for some reason, it could be specified explicitly by pointing dnsmasq to the file which is created by NetworkManager whenever it connects or reconnects to a network:

resolv-file=/run/NetworkManager/no-stub-resolv.conf

dnsmasq config file: /etc/dnsmasq.d/dns-int.conf:

no-resolv
server=/int/10.1.1.1
server=/org/10.1.1.1
server=/test.net/10.1.1.1
no-poll
domain-needed
strict-order
clear-on-reload
no-negcache
log-queries

In /etc/NetworkManager/NetworkManager.conf, under section [main]:

dns=dnsmasq

Add a symlink to the config directory used by NetworkManager pointing to the config file that would be used when starting dnsmasq directly using systemctl start dnsmasq:

`/etc/NetworkManager/dnsmasq.d/dns-int.conf` -> `/etc/dnsmasq.d/dns-int.conf`

Please note: My initial attempt failed because dnsmasq forwarded all queries to any of the internal domains listed above not only to the internal nameserver 10.1.1.1 but also to the default nameserver assigned by DHCP:

$ sudo grep dnsmasq /var/log/messages | grep forward | grep test.net
May  3 10:06:52 ... dnsmasq[4128385]: forwarded foo.test.net to 10.1.1.1
May  3 10:06:52 ... dnsmasq[4128385]: forwarded foo.test.net to 192.168.1.1

Now, it doesn't seem to do that anymore, not sure why it did that in the first place.

Additionally, I tried to block queries to the search domain "intern" by adding this to the config file:

address=/intern/

According to the man page, Queries in the domains are never forwarded, but instead:

forwarded foo.intern to 192.168.1.1

Tried a fake address:

address=/intern/127.0.0.2
... dnsmasq[95222]: query[A] foo.intern from 127.0.0.1
... dnsmasq[95222]: config foo.intern is 127.0.0.2
... dnsmasq[95222]: query[AAAA] foo.intern from 127.0.0.1
... dnsmasq[95222]: forwarded foo.intern to 192.168.1.1
$ host foo.intern localhost
Using domain server:
Name: localhost
Address: 127.0.0.1#53
Aliases: 

foo.intern has address 127.0.0.2
Host foo.intern not found: 3(NXDOMAIN)
Host foo.intern not found: 4(NOTIMP)

This way, it's leaking IPv6 queries. And with this special setting:

address=/intern/#

It's leaking MX queries:

... dnsmasq[97107]: query[AAAA] foo.intern from 127.0.0.1
... dnsmasq[97107]: config foo.intern is ::
... dnsmasq[97107]: query[MX] foo.intern from 127.0.0.1
... dnsmasq[97107]: forwarded foo.intern to 192.168.1.1
... dnsmasq[97107]: reply error is not implemented

In other words, when you think you've prevented a dns leak, a new one pops up. All of this happens when dnsmasq is started by NetworkManager, just in case it makes a difference (because address=/intern/ appears to work if dnsmasq is started manually).

Other than that, it seems to work for the most part but still, it would be preferred to have a working configuration for systemd-resolved.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.