[Dnsmasq-discuss] [PATCH] Answer NODATA for --address= names under a --local= domain

Dominik Derigs dl6er at dl6er.de
Wed Aug 26 05:40:43 UTC 2026


Hi Simon,

with these two lines, on 2.93 and on current master:

     local=/lan/
     address=/direct.lan/10.0.0.5

A for direct.lan returns 10.0.0.5 and AAAA for the same name returns 
NXDOMAIN.

I am sending this as a question about intent rather than a straight bug 
report,
because the two options are separate declarations and you may have meant the
--local= to win. However, NXDOMAIN is obviously not a harmless here. It 
says the
name does not exist, one query after dnsmasq answered the A query, and 
clients
believe it: musl's getaddrinfo() treats NXDOMAIN on either half of an 
AF_UNSPEC
lookup as a total failure, so the name stops resolving altogether on 
Alpine and
similar systems (most docker containers). The A-only local override 
quietly stops
overriding, and it is hard to diagnose because dig A looks perfectly 
healthy.
IMO, NODATA is the correct answer here.

What further makes me think this is not intended is that three 
neighboring paths already
answer NODATA in the same situation:

   * --host-record=hr.lan,10.0.0.4 under local=/lan/, where
     check_for_local_domain() finds the cache entry.

   * local=/wa.lan/ paired with address=/wa.lan/10.0.0.9, where the 
rollback in
     is_local_answer() reaches the SERV_4ADDR entry in the same group.

   * A forwarded query that upstream answers NXDOMAIN, which process_reply()
     converts using check_for_local_domain() || lookup_domain(name, 
F_CONFIG,
     NULL, NULL).

Only the case where the --address= sits in a longer domain group than the
--local= returns NXDOMAIN, and nothing about that case makes the name 
any less
existent than in the other three.

The patch gives is_local_answer() the second half of the test that
process_reply() already performs in full, restricted to literal 
addresses in a
domain at least as specific as the one that matched. The restriction 
matters:
with address=/example.com/10.0.0.8 and local=/sub.example.com/, the parent
wildcard is already shadowed for A, so sub.example.com does not exist 
and must
keep answering NXDOMAIN for every type. Calling lookup_domain() unrestricted
would turn that into NODATA and produce the same contradiction in the other
direction. That case is unreachable in process_reply(), since a name under
--local= is never forwarded.

Reproducer, loopback only, config lines as above:

     dig @localhost direct.lan A       -> NOERROR, 10.0.0.5
     dig @localhost direct.lan AAAA    -> NXDOMAIN, and NODATA with the 
patch

Downstream report from a user hitting this in the wild:
https://github.com/pi-hole/FTL/issues/3039

I attached a patch that seems to fix this behavior in my tests.


Best regards,
Dominik
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Answer-NODATA-for-address-names-under-a-local-domain.patch
Type: text/x-patch
Size: 2884 bytes
Desc: not available
URL: <http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/attachments/20260826/04c71197/attachment.bin>


More information about the Dnsmasq-discuss mailing list