From 63ba726e1f8d1ac53db260110657bc82539b2d97 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sun, 3 Dec 2023 17:48:56 +0000 Subject: [PATCH] Fix --synth-domain NXDOMAIN responses. By design, dnsmasq forwards queries for RR-types it has no data on, even if it has data for the same domain and other RR-types. This can lead to an inconsitent view of the DNS when an upstream server returns NXDOMAIN for an RR-type and domain but the same domain but a different RR-type gets an answer from dnsmasq. To avoid this, dnsmasq converts NXDOMAIN answer from upstream to NODATA answers if it would answer a query for the domain and a different RR-type. An oversight missed out --synth-domain from the code to do this, so --synth-domain=thekelleys.org.uk,192.168.0.0/24 would result in the correct answer to an A query for 192-168.0.1.thekelleys.org.uk and an AAAA query for the same domain would be forwarded upstream and the resulting NXDOMAIN reply returned. After the fix, the reply gets converted to NODATA. Thanks to Matt Wong for spotting the bug. --- src/domain.c | 22 ++++++++++++++-------- src/rfc1035.c | 4 ++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/domain.c b/src/domain.c index ca3931d..70fe1be 100644 --- a/src/domain.c +++ b/src/domain.c @@ -22,12 +22,13 @@ static int match_domain(struct in_addr addr, struct cond_domain *c); static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c); static int match_domain6(struct in6_addr *addr, struct cond_domain *c); -int is_name_synthetic(int flags, char *name, union all_addr *addr) +int is_name_synthetic(int flags, char *name, union all_addr *addrp) { char *p; struct cond_domain *c = NULL; int prot = (flags & F_IPV6) ? AF_INET6 : AF_INET; - + union all_addr addr; + for (c = daemon->synth_domains; c; c = c->next) { int found = 0; @@ -74,7 +75,7 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr) if (!c->is6 && index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr)) { - addr->addr4.s_addr = htonl(ntohl(c->start.s_addr) + index); + addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index); found = 1; } } @@ -86,8 +87,8 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr) index <= addr6part(&c->end6) - addr6part(&c->start6)) { u64 start = addr6part(&c->start6); - addr->addr6 = c->start6; - setaddr6part(&addr->addr6, start + index); + addr.addr6 = c->start6; + setaddr6part(&addr.addr6, start + index); found = 1; } } @@ -135,8 +136,8 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr) } } - if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr)) - found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c); + if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, &addr)) + found = (prot == AF_INET) ? match_domain(addr.addr4, c) : match_domain6(&addr.addr6, c); } /* restore name */ @@ -148,7 +149,12 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr) if (found) - return 1; + { + if (addrp) + *addrp = addr; + + return 1; + } } return 0; diff --git a/src/rfc1035.c b/src/rfc1035.c index ae6b46a..7f0450c 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1213,6 +1213,10 @@ int check_for_local_domain(char *name, time_t now) if (cache_find_non_terminal(name, now)) return 1; + if (is_name_synthetic(F_IPV4, name, NULL) || + is_name_synthetic(F_IPV6, name, NULL)) + return 1; + return 0; }