diff --git a/src/forward.c b/src/forward.c index 14cdfaa..a077620 100644 --- a/src/forward.c +++ b/src/forward.c @@ -120,8 +120,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne unsigned int flags = 0; for (serv = daemon->servers; serv; serv=serv->next) + if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC)) + continue; /* domain matches take priority over NODOTS matches */ - if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0) + else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0) { unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; *type = SERV_FOR_NODOTS; @@ -877,10 +879,10 @@ void reply_query(int fd, int family, time_t now) return; /* Truncated answer can't be validated. - If this is an answer to a DNSSEC-generated query, we still - need to get the client to retry over TCP, so return - an answer with the TC bit set, even if the actual answer fits. - */ + If this is an answer to a DNSSEC-generated query, we still + need to get the client to retry over TCP, so return + an answer with the TC bit set, even if the actual answer fits. + */ if (header->hb3 & HB3_TC) status = STAT_TRUNCATED; @@ -933,37 +935,35 @@ void reply_query(int fd, int family, time_t now) /* Find server to forward to. This will normally be the same as for the original query, but may be another if servers for domains are involved. */ - if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0) + if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0) { struct server *start = server, *new_server = NULL; - type &= ~SERV_DO_DNSSEC; - - while (1) - { - if (type == (start->flags & SERV_TYPE) && - (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && - !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) - { - new_server = start; - if (server == start) - { - new_server = NULL; - break; - } - } - - if (!(start = start->next)) - start = daemon->servers; - if (start == server) - break; - } - - if (new_server) - server = new_server; + + while (1) + { + if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) && + (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && + !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) + { + new_server = start; + if (server == start) + { + new_server = NULL; + break; + } + } + + if (!(start = start->next)) + start = daemon->servers; + if (start == server) + break; + } + + if (new_server) + server = new_server; } - + new->sentto = server; - new->rfd4 = NULL; #ifdef HAVE_IPV6 new->rfd6 = NULL; @@ -1506,14 +1506,12 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si /* Find server to forward to. This will normally be the same as for the original query, but may be another if servers for domains are involved. */ - if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) != 0) + if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0) { new_status = STAT_ABANDONED; break; } - type &= ~SERV_DO_DNSSEC; - while (1) { if (!firstsendto) @@ -1530,34 +1528,34 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si } } - if (type != (server->flags & SERV_TYPE) || + if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) || (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) || (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) continue; - - retry: - /* may need to make new connection. */ - if (server->tcpfd == -1) - { - if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1) - continue; /* No good, next server */ - -#ifdef HAVE_CONNTRACK - /* Copy connection mark of incoming query to outgoing connection. */ - if (have_mark) - setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); -#endif - - if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) || - connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1) - { - close(server->tcpfd); - server->tcpfd = -1; + + retry: + /* may need to make new connection. */ + if (server->tcpfd == -1) + { + if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1) continue; /* No good, next server */ - } - - server->flags &= ~SERV_GOT_TCP; - } + +#ifdef HAVE_CONNTRACK + /* Copy connection mark of incoming query to outgoing connection. */ + if (have_mark) + setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); +#endif + + if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) || + connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1) + { + close(server->tcpfd); + server->tcpfd = -1; + continue; /* No good, next server */ + } + + server->flags &= ~SERV_GOT_TCP; + } if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) || !read_write(server->tcpfd, &c1, 1, 1) || @@ -2080,6 +2078,8 @@ static void free_frec(struct frec *f) #endif } + + /* if wait==NULL return a free or older than TIMEOUT record. else return *wait zero if one available, or *wait is delay to when the oldest in-use record will expire. Impose an absolute @@ -2126,7 +2126,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force) /* can't find empty one, use oldest if there is one and it's older than timeout */ - if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT) + if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT) { /* keep stuff for twice timeout if we can by allocating a new record instead */ @@ -2166,7 +2166,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force) return f; /* OK if malloc fails and this is NULL */ } - + /* crc is all-ones if not known. */ static struct frec *lookup_frec(unsigned short id, void *hash) {