I want to have dnsmasq
handle incoming DNS queries first, and only forward the question to systemd-resolved
if dnsmasq itself does not have the answer.
To be very clear: I know how to disable systemd-resolved
's "DNSStubListener", so that dnsmasq
is the only DNS server running on my system, but that is not what I'm asking.
As far as I've understood it, this means that I need to have systemd-resolved
's stub resolver running, but I also need to make sure systemd-resolved
doesn't answer the inbound DNS query before dnsmasq
does. But how?
(As to the reason why: I want to use the DNS server pointed to by DHCP for "normal" Internet traffic, which means I cannot hard-code upstream DNS servers in the dnsmasq
config file. But I also want to have dnsmasq
handle DNS blocking, special host names for locally running VMs, routing some but not all traffic via a VPN connection, or similar situations.)
Could I use the "DNSStubListener=no" option for systemd-resolved
, but also define "DNSStubListenerExtra=....", with localhost as the IP address but a non-standard port number, and use that address as dnsmasq
's primary upstream DNS server? Would that kind of setup be stable?
Edit (after answers already provided): This is on Ubuntu 24.04 Desktop.
You didn't specify what version of Ubuntu you're using. The following is based on Ubuntu 24.04 Server.
If I understand what you want to do correctly, you want to setup Dnsmasq as your primary DNS resolver on the localhost and use
systemd-resolved
as it's forwarding server instead of any uplink servers. Thus, you wantsystemd-resolved
to forward to any uplink servers but not cache any queries. You ultimately want caching to be left to Dnsmasq.So, a few things need to be done:
127.0.0.1
on port 53/etc/resolv.conf
for any nameserverssystemd-resolved
as its forwarding server, which in turn uses any uplink servers provided via DHCP./etc/resolv.conf
:127.0.0.1
as a nameserver. Although Dnsmasq will not be referencing this file, it is referenced by many applications when doing a DNS query. For example,dig
andping
. So you want those applications to query Dnsmasq via127.0.0.1
.systemd-resolved
:127.0.0.53
on port53
127.0.0.1
on port5353
Assuming Dnsmasq is already installed, start by stopping both
systemd-resolved
anddnsmasq
:1. Configure
dnsmasq
Edit
/etc/default/dnsmasq
and define the following:Both of these need to be defined even though the
resolvconf
application is not installed by default on Ubuntu 24.04 Server. This is due to/sbin/resolvconf
being a symlink to/bin/resolvectl
. For more information, see the Note below.Edit
/etc/dnsmasq.conf
and define the following:bind-interfaces
is defined so that the service does not listening on all addresses on all interfaces. This setup is for the service to only listen on the loopback interface and no external interfaces. Additionally, the service is only listening on127.0.0.1:53
instead of0.0.0.0:53
.From the Dnsmasq manpage:
Start
dnsmasq
service and check it's status:Check that it's listening on port
53
at127.0.0.1
:2. Create new
/etc/resolv.conf
Remove
/etc/resolv.conf
Create a new
/etc/resolv.conf
with the Dnsmasq nameserver:3. Configure
systemd-resolved
Edit
/etc/systemd/resolved.conf
and define the following:This disables the Stub listener for
systemd-resolved
at127.0.0.53:53
and allows it to listen on address127.0.0.1:5353
.From the resolved.conf(5) man page:
Start
systemd-resolved
service and check it's status:Check that it's listening on port
5353
at127.0.0.1
:Testing
Run a query. If configured correctly, the query should resolve.
To test that it's going through
systemd-resolved
you need to restart Dnsmasq to clear the cache and then stopsystemd-resolved
before re-running the query.I emphasize this, because
systemd-resolved
will start whenever Dnsmasq is restarted. See Note below.Therefore:
Restart Dnsmasq to clear the cache
sudo systemctl restart dnsmasq
Stop
systemd-resolved
sudo systemctl stop systemd-resolved
Check that
systemd-resolved
is not runningsystemctl status systemd-resolved
orps -aux | grep systemd-resolved
Re-run query. It should time out.
Caching
The original question asked to disable caching within
systemd-resolved
and leave it exclusively to Dnsmasq. While this can be done, there might be a benefit to switching it around the other way. As @kos indicated in a comment,systemd-resolved
is also queried via D-Bus, which would be able to take advantage of caching if it was enabled forsystemd-resolved
.Therefore, it's very easy to configure this so that caching is enabled for
systemd-resolved
and caching is disabled for Dnsmasq.Edit
/etc/dnsmasq.conf
and define the following to disable cache for Dnsmasq:Per the Dnsmasq manpage:
Edit
/etc/systemd/resolved.conf
and comment out as follows to re-enable caching forsystemd-resolved
, which is the default setting:Note
Whenever the Dnsmasq service is stopped and started, the service calls a helper script,
/usr/share/dnsmasq/systemd-helper
. This references another file,/usr/share/dnsmasq/init-system-common
. Whenever Dnsmasq is stopped,/sbin/resolvconf
is called with the following:Notice that
/sbin/resolvconf
is called, and as I mentioned earlier,/sbin/resolvconf
is a symlink to/bin/resolvctl
.Therefore, since
resolvectl
is a component ofsystemd-resolved
, it will startsystemd-resolved
. More info can be found here.I mention this, because when testing, you'll find that
systemd-resolved
will start automatically without you knowing it.Interestingly,
/sbin/resolvconf
is also called when starting Dnsmasq service.But if you recall, we defined
DNSMASQ_EXCEPT="lo"
in/etc/default/dnsmasq
. As such,/sbin/resolvconf
isn't called when starting Dnsmasq but would be if this wasn't defined.If you've ever seen the following error when looking at the output of
systemctl status dnsmasq
, this is becauseDNSMASQ_EXCEPT="lo"
is not defined(commented out) and it's trying to register DNS settings associated with the loopback device, which it can't do.This error can be seen by running the command directly:
Edit: A much more elaborate answer was given above Original answer below
Yep, it seemed to work.
I.e., I did this:
In
/etc/systemd/resolved.conf.d/dnsmasqcompatibility.conf
:And in /etc/dnsmasq.conf:
By typing this in a terminal
host www.google.com 127.0.0.1
, I got this:And this was in
/var/log/dnsmasq.log
:(and so on)
I could also confirm that by stopping the
systemd-resolved
service, DNS lookups timed out.I should probably also add
no-resolv
to/etc/dnsmasq.conf
, to force all queries to be passed to port 5053, but I don't know if that would make any difference since it would be using the DNS servers known tosystemd-resolved
anyway, regardless if the IP addresses were taken from a file or from a second DNS server (via forwarded query).Let systemd-resolved handle DHCP servers and use server=127.0.0.53 in Dnsmasq. Have /etc/resolv.conf pointed to 127.0.0.1 where Dnsmasq is listening. But you would hit issues of systemd-resolved, for example buggy DNSSec validation. You have been warned.