Commit 09f3b2cd authored by Simon Kelley's avatar Simon Kelley

Fix case of DS queries to domains marked as not doing DNSSEC.

This was causing confusion: DNSSEC queries would be sent to
servers for domains that don't do DNSSEC, but because of that status
the answers would be treated as answers to ordinary queries,
sometimes resulting in a crash.
parent 22827870
...@@ -120,8 +120,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne ...@@ -120,8 +120,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
unsigned int flags = 0; unsigned int flags = 0;
for (serv = daemon->servers; serv; serv=serv->next) 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 */ /* 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; unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
*type = SERV_FOR_NODOTS; *type = SERV_FOR_NODOTS;
...@@ -877,10 +879,10 @@ void reply_query(int fd, int family, time_t now) ...@@ -877,10 +879,10 @@ void reply_query(int fd, int family, time_t now)
return; return;
/* Truncated answer can't be validated. /* Truncated answer can't be validated.
If this is an answer to a DNSSEC-generated query, we still If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits. an answer with the TC bit set, even if the actual answer fits.
*/ */
if (header->hb3 & HB3_TC) if (header->hb3 & HB3_TC)
status = STAT_TRUNCATED; status = STAT_TRUNCATED;
...@@ -933,37 +935,35 @@ void reply_query(int fd, int family, time_t now) ...@@ -933,37 +935,35 @@ void reply_query(int fd, int family, time_t now)
/* Find server to forward to. This will normally be the /* Find server to forward to. This will normally be the
same as for the original query, but may be another if same as for the original query, but may be another if
servers for domains are involved. */ 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; struct server *start = server, *new_server = NULL;
type &= ~SERV_DO_DNSSEC;
while (1)
while (1) {
{ if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
if (type == (start->flags & SERV_TYPE) && (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) {
{ new_server = start;
new_server = start; if (server == start)
if (server == start) {
{ new_server = NULL;
new_server = NULL; break;
break; }
} }
}
if (!(start = start->next))
if (!(start = start->next)) start = daemon->servers;
start = daemon->servers; if (start == server)
if (start == server) break;
break; }
}
if (new_server)
if (new_server) server = new_server;
server = new_server;
} }
new->sentto = server; new->sentto = server;
new->rfd4 = NULL; new->rfd4 = NULL;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
new->rfd6 = NULL; new->rfd6 = NULL;
...@@ -1506,14 +1506,12 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si ...@@ -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 /* Find server to forward to. This will normally be the
same as for the original query, but may be another if same as for the original query, but may be another if
servers for domains are involved. */ 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; new_status = STAT_ABANDONED;
break; break;
} }
type &= ~SERV_DO_DNSSEC;
while (1) while (1)
{ {
if (!firstsendto) if (!firstsendto)
...@@ -1530,34 +1528,34 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si ...@@ -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)) || (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) (server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
continue; continue;
retry: retry:
/* may need to make new connection. */ /* may need to make new connection. */
if (server->tcpfd == -1) if (server->tcpfd == -1)
{ {
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1) if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */ continue; /* No good, next server */
#ifdef HAVE_CONNTRACK #ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */ /* Copy connection mark of incoming query to outgoing connection. */
if (have_mark) if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif #endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) || if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1) connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{ {
close(server->tcpfd); close(server->tcpfd);
server->tcpfd = -1; server->tcpfd = -1;
continue; /* No good, next server */ continue; /* No good, next server */
} }
server->flags &= ~SERV_GOT_TCP; server->flags &= ~SERV_GOT_TCP;
} }
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) || if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
!read_write(server->tcpfd, &c1, 1, 1) || !read_write(server->tcpfd, &c1, 1, 1) ||
...@@ -2080,6 +2078,8 @@ static void free_frec(struct frec *f) ...@@ -2080,6 +2078,8 @@ static void free_frec(struct frec *f)
#endif #endif
} }
/* if wait==NULL return a free or older than TIMEOUT record. /* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to else return *wait zero if one available, or *wait is delay to
when the oldest in-use record will expire. Impose an absolute 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) ...@@ -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 /* can't find empty one, use oldest if there is one
and it's older than timeout */ 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 /* keep stuff for twice timeout if we can by allocating a new
record instead */ record instead */
...@@ -2166,7 +2166,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force) ...@@ -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 */ return f; /* OK if malloc fails and this is NULL */
} }
/* crc is all-ones if not known. */ /* crc is all-ones if not known. */
static struct frec *lookup_frec(unsigned short id, void *hash) static struct frec *lookup_frec(unsigned short id, void *hash)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment