Fix specific NOERR/NXDOMAIN confusion.

In the specific case of configuring an A record for a domain

address=/example.com/1.2.3.4

queries for *example.com for any other type will now return
NOERR, and not the previous erroneous NXDOMAIN. The same thing
applies for

address=/example.com/::1:2:3:4
address=/example.com/#
This commit is contained in:
Simon Kelley
2021-06-17 23:11:17 +01:00
parent 6860cf932b
commit d0ae3f5a4d
2 changed files with 54 additions and 34 deletions

View File

@@ -75,6 +75,8 @@ void build_server_array(void)
A flag of F_DNSSECOK returns a DNSSEC capable server only and A flag of F_DNSSECOK returns a DNSSEC capable server only and
also disables NODOTS servers from consideration. also disables NODOTS servers from consideration.
A flag of F_DOMAINSRV returns a domain-specific server only. A flag of F_DOMAINSRV returns a domain-specific server only.
A flag of F_CONFIG returns anything that generates a local
reply of IPv4 or IPV6.
return 0 if nothing found, 1 otherwise. return 0 if nothing found, 1 otherwise.
*/ */
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout) int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
@@ -85,8 +87,6 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
int nlow = 0, nhigh = 0; int nlow = 0, nhigh = 0;
char *cp; char *cp;
int compares = 0;
/* may be no configured servers. */ /* may be no configured servers. */
if (daemon->serverarraysz == 0) if (daemon->serverarraysz == 0)
return 0; return 0;
@@ -121,8 +121,6 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
{ {
try = (low + high)/2; try = (low + high)/2;
compares++;
if ((rc = order(qdomain, leading_dot, qlen, daemon->serverarray[try])) == 0) if ((rc = order(qdomain, leading_dot, qlen, daemon->serverarray[try])) == 0)
break; break;
@@ -186,8 +184,6 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
qdomain += crop_query; qdomain += crop_query;
} }
printf("compares: %d\n", compares);
/* domain has no dots, and we have at least one server configured to handle such, /* domain has no dots, and we have at least one server configured to handle such,
These servers always sort to the very end of the array. These servers always sort to the very end of the array.
A configured server eg server=/lan/ will take precdence. */ A configured server eg server=/lan/ will take precdence. */
@@ -240,6 +236,14 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
See which of those match our query in that priority order and narrow (low, high) */ See which of those match our query in that priority order and narrow (low, high) */
#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
for (i = nlow; (flags & F_CONFIG) && i < nhigh && (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS); i++);
if (i != nlow)
nhigh = i;
else
{
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++); for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
if (i != nlow && (flags & F_IPV6)) if (i != nlow && (flags & F_IPV6))
@@ -280,6 +284,7 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
} }
} }
} }
}
*lowout = nlow; *lowout = nlow;
*highout = nhigh; *highout = nhigh;
@@ -301,7 +306,19 @@ int is_local_answer(time_t now, int first, char *name)
else if (flags & SERV_ALL_ZEROS) else if (flags & SERV_ALL_ZEROS)
rc = F_IPV4 | F_IPV6; rc = F_IPV4 | F_IPV6;
else else
rc = check_for_local_domain(name, now) ? F_NOERR : F_NXDOMAIN; {
/* argument first is the first struct server which matches the query type;
now roll back to the server which is just the same domain, to check if that
provides an answer of a different type. */
for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
check_for_local_domain(name, now))
rc = F_NOERR;
else
rc = F_NXDOMAIN;
}
} }
return rc; return rc;

View File

@@ -663,8 +663,10 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
int doctored = 0; int doctored = 0;
if (rcode == NXDOMAIN && if (rcode == NXDOMAIN &&
extract_request(header, n, daemon->namebuff, NULL) && extract_request(header, n, daemon->namebuff, NULL))
check_for_local_domain(daemon->namebuff, now)) {
if (check_for_local_domain(daemon->namebuff, now) ||
lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL))
{ {
/* if we forwarded a query for a locally known name (because it was for /* if we forwarded a query for a locally known name (because it was for
an unknown type) and the answer is NXDOMAIN, convert that to NODATA, an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
@@ -674,6 +676,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
SET_RCODE(header, NOERROR); SET_RCODE(header, NOERROR);
cache_secure = 0; cache_secure = 0;
} }
}
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored)) if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
{ {