From: Simon Kelley Date: Tue, 12 Jan 2016 15:58:23 +0000 (+0000) Subject: Disable DNSSEC for server=/domain/.. servers unless trust-anchor provided. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=367341f7456c33c66142d66b0e76c56d53bca4f2;p=people%2Fms%2Fdnsmasq.git Disable DNSSEC for server=/domain/.. servers unless trust-anchor provided. --- diff --git a/src/dnsmasq.h b/src/dnsmasq.h index b2d1c5e..543481c 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -477,6 +477,7 @@ union mysockaddr { #define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */ #define SERV_FROM_FILE 4096 /* read from --servers-file */ #define SERV_LOOP 8192 /* server causes forwarding loop */ +#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */ struct serverfd { int fd; diff --git a/src/dnssec.c b/src/dnssec.c index 18efa59..ebb9c93 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1892,7 +1892,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now) break; } } - + /* Now work away from the trust anchor */ while (1) { diff --git a/src/forward.c b/src/forward.c index 1458578..11c0d45 100644 --- a/src/forward.c +++ b/src/forward.c @@ -106,8 +106,8 @@ int send_from(int fd, int nowild, char *packet, size_t len, return 1; } -static unsigned int search_servers(time_t now, struct all_addr **addrpp, - unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind) +static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype, + char *qdomain, int *type, char **domain, int *norebind) { /* If the query ends in the domain in one of our servers, set @@ -175,7 +175,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, if (domainlen >= matchlen) { - *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND); + *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC); *domain = serv->domain; matchlen = domainlen; if (serv->flags & SERV_NO_ADDR) @@ -233,12 +233,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, struct frec *forward, int ad_reqd, int do_bit) { char *domain = NULL; - int type = 0, norebind = 0; + int type = SERV_DO_DNSSEC, norebind = 0; struct all_addr *addrp = NULL; unsigned int flags = 0; struct server *start = NULL; #ifdef HAVE_DNSSEC void *hash = hash_questions(header, plen, daemon->namebuff); + int do_dnssec = 0; #else unsigned int crc = questions_crc(header, plen, daemon->namebuff); void *hash = &crc; @@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, daemon->last_server = NULL; } type = forward->sentto->flags & SERV_TYPE; +#ifdef HAVE_DNSSEC + do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC; +#endif + if (!(start = forward->sentto->next)) start = daemon->servers; /* at end of list, recycle */ header->id = htons(forward->new_id); @@ -324,6 +329,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, if (gotname) flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); +#ifdef HAVE_DNSSEC + do_dnssec = type & SERV_DO_DNSSEC; + type &= ~SERV_DO_DNSSEC; +#endif + if (!flags && !(forward = get_new_frec(now, NULL, 0))) /* table full - server failure. */ flags = F_NEG; @@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, } #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN)) + if (option_bool(OPT_DNSSEC_VALID) && do_dnssec) { size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ); @@ -858,7 +868,7 @@ void reply_query(int fd, int family, time_t now) no_cache_dnssec = 1; #ifdef HAVE_DNSSEC - if (server && !(server->flags & SERV_HAS_DOMAIN) && + if (server && (server->flags & SERV_DO_DNSSEC) && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED)) { int status = 0; @@ -1640,6 +1650,10 @@ unsigned char *tcp_request(int confd, time_t now, if (gotname) flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); +#ifdef HAVE_DNSSEC + type &= ~SERV_DO_DNSSEC; +#endif + if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server) last_server = daemon->servers; else @@ -1711,7 +1725,7 @@ unsigned char *tcp_request(int confd, time_t now, } #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID)) + if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC)) { new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536); @@ -1757,7 +1771,7 @@ unsigned char *tcp_request(int confd, time_t now, #endif #ifdef HAVE_DNSSEC - if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled) + if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC)) { int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */ int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount); diff --git a/src/network.c b/src/network.c index 66b91ad..303ae50 100644 --- a/src/network.c +++ b/src/network.c @@ -1430,12 +1430,38 @@ void check_servers(void) if (!option_bool(OPT_NOWILD)) enumerate_interfaces(0); +#ifdef HAVE_DNSSEC + /* Disable DNSSEC validation when using server=/domain/.... servers + unless there's a configured trust anchor. */ + for (serv = daemon->servers; serv; serv = serv->next) + serv->flags |= SERV_DO_DNSSEC; +#endif + for (serv = daemon->servers; serv; serv = serv->next) { - if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) + if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) { - port = prettyprint_addr(&serv->addr, daemon->namebuff); +#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) + serv->flags &= ~SERV_DO_DNSSEC; + } +#endif + + port = prettyprint_addr(&serv->addr, daemon->namebuff); + /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */ if (serv->addr.sa.sa_family == AF_INET && serv->addr.in.sin_addr.s_addr == 0) @@ -1471,7 +1497,11 @@ void check_servers(void) { if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV)) { - char *s1, *s2; + char *s1, *s2, *s3 = ""; +#ifdef HAVE_DNSSEC + if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC)) + s3 = _("(no DNSSEC)"); +#endif if (!(serv->flags & SERV_HAS_DOMAIN)) s1 = _("unqualified"), s2 = _("names"); else if (strlen(serv->domain) == 0) @@ -1484,7 +1514,7 @@ void check_servers(void) else if (serv->flags & SERV_USE_RESOLV) my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2); else - my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2); + my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3); } #ifdef HAVE_LOOP else if (serv->flags & SERV_LOOP)