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.
This commit is contained in:
Simon Kelley
2023-12-03 17:48:56 +00:00
parent f1beb79429
commit 63ba726e1f
2 changed files with 18 additions and 8 deletions

View File

@@ -22,11 +22,12 @@ 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)
{
@@ -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;

View File

@@ -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;
}