From 92be34a4077672f592d47e2991b3530305517a28 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sat, 16 Jan 2016 18:39:54 +0000 Subject: [PATCH] Complete work to allow DNSSEC validation with private DNS servers. --- man/dnsmasq.8 | 5 ++++- src/forward.c | 34 +++++++++++++++++++++++++++++++--- src/network.c | 33 +++++++++++++++++++-------------- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index d51b10f..69acdae 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -405,7 +405,10 @@ xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving the flag .B -S /internal.thekelleys.org.uk/192.168.1.1 will send all queries for internal machines to that nameserver, everything else will go to the -servers in /etc/resolv.conf. An empty domain specification, +servers in /etc/resolv.conf. DNSSEC validation is turned off for such +private nameservers, UNLESS a +.B --trust-anchor +is specified for the domain in question. An empty domain specification, .B // has the special meaning of "unqualified names only" ie names without any dots in them. A non-standard port may be specified as diff --git a/src/forward.c b/src/forward.c index 11c0d45..c48fd75 100644 --- a/src/forward.c +++ b/src/forward.c @@ -151,7 +151,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne hostname_isequal(matchstart, serv->domain) && (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' )) { - if (serv->flags & SERV_NO_REBIND) + if ((serv->flags & SERV_NO_REBIND) && norebind) *norebind = 1; else { @@ -644,7 +644,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server return resize_packet(header, n, pheader, plen); /* Complain loudly if the upstream server is non-recursive. */ - if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 && + if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && server && !(server->flags & SERV_WARNED_RECURSIVE)) { prettyprint_addr(&server->addr, daemon->namebuff); @@ -923,12 +923,40 @@ void reply_query(int fd, int family, time_t now) status = STAT_ABANDONED; else { - int fd; + int fd, type; struct frec *next = new->next; + char *domain; + *new = *forward; /* copy everything, then overwrite */ new->next = next; new->blocking_query = NULL; + + /* 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) + { + struct server *start = server; + 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))) + { + server = start; + break; + } + + if (!(start = start->next)) + start = daemon->servers; + if (start == server) + break; + } + } new->sentto = server; + new->rfd4 = NULL; #ifdef HAVE_IPV6 new->rfd6 = NULL; diff --git a/src/network.c b/src/network.c index 303ae50..5451c6c 100644 --- a/src/network.c +++ b/src/network.c @@ -1442,20 +1442,25 @@ void check_servers(void) if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) { #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID) && (serv->flags & SERV_HAS_DOMAIN)) - { - struct ds_config *ds; - char *domain = serv->domain; - - /* .example.com is valid */ - while (*domain == '.') - domain++; - - for (ds = daemon->ds; ds; ds = ds->next) - if (ds->name[0] != 0 && hostname_isequal(domain, ds->name)) - break; - - if (!ds) + if (option_bool(OPT_DNSSEC_VALID)) + { + if (serv->flags & SERV_HAS_DOMAIN) + { + struct ds_config *ds; + char *domain = serv->domain; + + /* .example.com is valid */ + while (*domain == '.') + domain++; + + for (ds = daemon->ds; ds; ds = ds->next) + if (ds->name[0] != 0 && hostname_isequal(domain, ds->name)) + break; + + if (!ds) + serv->flags &= ~SERV_DO_DNSSEC; + } + else if (serv->flags & SERV_FOR_NODOTS) serv->flags &= ~SERV_DO_DNSSEC; } #endif