From: Simon Kelley Date: Tue, 29 Apr 2025 15:33:22 +0000 (+0100) Subject: Fix some edge cases wth domains and --address and --server. X-Git-Tag: v2.92test5^0 X-Git-Url: https://thekelleys.org.uk/gitweb/?a=commitdiff_plain;h=e86d53c438571e24d0491d03d553f48a262def91;p=dnsmasq.git Fix some edge cases wth domains and --address and --server. Consider what happens when the same domain appears in --address and --server. This commit fixes the order, I think correctly like this: highest to lowest priority. --address with a IPv4 or IPv6 address (as long as the query matches the type) --address with # for all-zeros, as long as the query is A or AAAA) --address with no address, which returns NXDOMAIN or NOERROR for all types. --server with address set to # to use the unqualified servers. --server with matching domain. --server without domain or from /etc/resolv.conf. Note that the above is only valid when same domain appears. The domain being matched is determined first, and has a higher priority, so you can send google.com to a server and force com to return NXDOMAIN and for google.com the server config will override the address config, because there's a longer match. --- diff --git a/src/dnsmasq.h b/src/dnsmasq.h index c310597..5c4fd4c 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -558,9 +558,9 @@ union mysockaddr { /* The actual values here matter, since we sort on them to get records in the order - IPv6 addr, IPv4 addr, all zero return, resolvconf servers, upstream server, no-data return */ -#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */ -#define SERV_USE_RESOLV 2 /* forward this domain in the normal way */ + IPv6 addr, IPv4 addr, all zero return, no-data return, resolvconf servers, upstream server */ +#define SERV_USE_RESOLV 1 /* forward this domain in the normal way */ +#define SERV_LITERAL_ADDRESS 2 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */ #define SERV_ALL_ZEROS 4 /* return all zeros for A and AAAA */ #define SERV_4ADDR 8 /* addr is IPv4 */ #define SERV_6ADDR 16 /* addr is IPv6 */ diff --git a/src/domain-match.c b/src/domain-match.c index cc8aa9b..a2e2266 100644 --- a/src/domain-match.c +++ b/src/domain-match.c @@ -20,7 +20,7 @@ static int order(char *qdomain, size_t qlen, struct server *serv); static int order_qsort(const void *a, const void *b); static int order_servers(struct server *s, struct server *s2); -/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */ +/* If the server is USE_RESOLV or LITERAL_ADDRESS, it lives on the local_domains chain. */ #define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS) void build_server_array(void) @@ -259,7 +259,6 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout) return 1; } -/* Return first server in group of equivalent servers; this is the "master" record. */ int server_samegroup(struct server *a, struct server *b) { return order_servers(a, b) == 0; @@ -296,11 +295,13 @@ int filter_servers(int seed, int flags, int *lowout, int *highout) } else { - /* Now the servers are on order between low and high, in the order - IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return. + /* Now the matching server records are all between low and high. + order_qsort() ensures that they are in the order + IPv6 addr, IPv4 addr, return zero for both, no-data return, + "use resolvconf" servers, domain-specific upstream servers. See which of those match our query in that priority order and narrow (low, high) */ - + for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++); if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6)) @@ -325,29 +326,27 @@ int filter_servers(int seed, int flags, int *lowout, int *highout) { nlow = i; - /* Short to resolv.conf servers */ - for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++); + /* now look for a NXDOMAIN answer --local=/domain/ */ + for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++); - if (i != nlow) + if (!(flags & (F_DOMAINSRV | F_SERVER)) && i != nlow) nhigh = i; else { - /* now look for a server */ - for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++); + nlow = i; + + /* return "use resolv.conf servers" if they exist */ + for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++); if (i != nlow) + nhigh = i; + else { /* If we want a server for a particular domain, and this one isn't, return nothing. */ if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0) nlow = nhigh; else - nhigh = i; - } - else - { - /* --local=/domain/, only return if we don't need a server. */ - if (flags & (F_DOMAINSRV | F_SERVER)) - nhigh = i; + nlow = i; } } } @@ -543,12 +542,14 @@ static int order_qsort(const void *a, const void *b) rc = order_servers(s1, s2); /* Sort all literal NODATA and local IPV4 or IPV6 responses together, - in a very specific order. We flip the SERV_LITERAL_ADDRESS bit - so the order is IPv6 literal, IPv4 literal, all-zero literal, - unqualified servers, upstream server, NXDOMAIN literal. */ + in a very specific order IPv6 literal, IPv4 literal, all-zero literal, + NXDOMAIN literal. We also include SERV_USE_RESOLV in this, so that + use-standard servers sort before ordinary servers. (SERV_USR_RESOLV set + implies that none of SERV_LITERAL_ADDRESS,SERV_4ADDR,SERV_6ADDR,SERV_ALL_ZEROS + are set) */ if (rc == 0) - rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) - - ((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS); + rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS | SERV_USE_RESOLV))) - + ((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS | SERV_USE_RESOLV))); /* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */ if (rc == 0) diff --git a/src/network.c b/src/network.c index 61742f6..68bc273 100644 --- a/src/network.c +++ b/src/network.c @@ -1665,7 +1665,7 @@ void check_servers(int no_loop_check) if (++locals <= LOCALS_LOGGED) my_syslog(LOG_INFO, _("using only locally-known addresses for %s"), serv->domain); } - else if (serv->flags & SERV_USE_RESOLV) + else if (serv->flags & SERV_USE_RESOLV && serv->domain_len != 0) my_syslog(LOG_INFO, _("using standard nameservers for %s"), serv->domain); }