From 1f60a18ea1c64beb8b6cffa0650a2bfad95ac352 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 11 May 2018 16:44:16 +0100 Subject: [PATCH 07/17] Retry SERVFAIL DNSSEC queries to a different server, if possible. Signed-off-by: Kevin Darbyshire-Bryant --- src/forward.c | 53 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) --- a/src/forward.c +++ b/src/forward.c @@ -825,9 +825,12 @@ void reply_query(int fd, int family, tim size_t plen; int is_sign; +#ifdef HAVE_DNSSEC /* For DNSSEC originated queries, just retry the query to the same server. */ if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) { + struct server *start; + blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); plen = forward->stash_len; @@ -839,26 +842,54 @@ void reply_query(int fd, int family, tim else log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec"); #endif - - if (forward->sentto->sfd) - fd = forward->sentto->sfd->fd; + + start = forward->sentto; + + /* for non-domain specific servers, see if we can find another to try. */ + if ((forward->sentto->flags & SERV_TYPE) == 0) + while (1) + { + if (!(start = start->next)) + start = daemon->servers; + if (start == forward->sentto) + break; + + if ((start->flags & SERV_TYPE) == 0 && + (start->flags & SERV_DO_DNSSEC)) + break; + } + + + if (start->sfd) + fd = start->sfd->fd; else { #ifdef HAVE_IPV6 - if (forward->sentto->addr.sa.sa_family == AF_INET6) - fd = forward->rfd6->fd; + if (start->addr.sa.sa_family == AF_INET6) + { + /* may have changed family */ + if (!forward->rfd6) + forward->rfd6 = allocate_rfd(AF_INET6); + fd = forward->rfd6->fd; + } else #endif - fd = forward->rfd4->fd; + { + /* may have changed family */ + if (!forward->rfd4) + forward->rfd4 = allocate_rfd(AF_INET); + fd = forward->rfd4->fd; + } } - + while (retry_send(sendto(fd, (char *)header, plen, 0, - &forward->sentto->addr.sa, - sa_len(&forward->sentto->addr)))); + &start->addr.sa, + sa_len(&start->addr)))); return; } - +#endif + /* In strict order mode, there must be a server later in the chain left to send to, otherwise without the forwardall mechanism, code further on will cycle around the list forwever if they @@ -1024,7 +1055,7 @@ void reply_query(int fd, int family, tim while (1) { if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) && - (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && + ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) { new_server = start;