diff --git a/src/dnsmasq.c b/src/dnsmasq.c index a264f77..a05f639 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -141,10 +141,18 @@ int main (int argc, char **argv) } #endif + if (option_bool(OPT_DNSSEC_VALID)) + { #ifdef HAVE_DNSSEC - if (daemon->cachesize dnskeys) + die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF); + + if (daemon->cachesize < CACHESIZ) + die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF); +#else + die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF); #endif + } #ifndef HAVE_TFTP if (option_bool(OPT_TFTP)) diff --git a/src/dnssec.c b/src/dnssec.c index 68b59e9..4caea9a 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1099,7 +1099,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch struct all_addr a; struct blockdata *key; struct crec *crecp; - + cache_start_insert(); for (p2 = ans_start, j = 0; j < ntohs(header->ancount) + ntohs(header->nscount); j++) diff --git a/src/forward.c b/src/forward.c index 31bb7bf..7af6f1f 100644 --- a/src/forward.c +++ b/src/forward.c @@ -855,42 +855,34 @@ void reply_query(int fd, int family, time_t now) and validate them with the new data. Failure to find needed data here is an internal error. Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates, return it to the original requestor. */ - if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) + while (forward->dependent) { - while (forward->dependent) - { - struct frec *prev; - - if (status == STAT_SECURE) - { - if (forward->flags & FREC_DNSKEY_QUERY) - status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); - else if (forward->flags & FREC_DS_QUERY) - status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); - } - - prev = forward->dependent; - free_frec(forward); - forward = prev; - forward->blocking_query = NULL; /* already gone */ - blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); - n = forward->stash_len; - } + struct frec *prev = forward->dependent; + free_frec(forward); + forward = prev; + forward->blocking_query = NULL; /* already gone */ + blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); + n = forward->stash_len; - /* All DNSKEY and DS records done and in cache, now finally validate original - answer, provided last DNSKEY is OK. */ if (status == STAT_SECURE) - status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class); - - if (status == STAT_NEED_DS || status == STAT_NEED_KEY) { - my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation")); - status = STAT_INSECURE; + if (forward->flags & FREC_DNSKEY_QUERY) + status = dnssec_validate_by_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); + else if (forward->flags & FREC_DS_QUERY) + status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); + else + status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class); + + if (status == STAT_NEED_DS || status == STAT_NEED_KEY) + { + my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation")); + status = STAT_INSECURE; + } } } if (status == STAT_TRUNCATED) - header->hb3 |= HB3_TC; + header->hb3 |= HB3_TC; else log_query(F_KEYTAG | F_SECSTAT, "result", NULL, status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS")); diff --git a/src/rfc1035.c b/src/rfc1035.c index 4c57c8d..ec2c7a9 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1710,32 +1710,33 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, } else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa))) { -#ifdef HAVE_DNSSEC - if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && - (crecp->flags & F_DNSSECOK) && - !(crecp->flags & F_NEG) && - sec_reqd && - option_bool(OPT_DNSSEC_VALID)) + if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd) { - int gotsig = 0; - - crecp = NULL; - while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY))) + if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))) + crecp = NULL; +#ifdef HAVE_DNSSEC + else if (crecp->flags & F_DNSSECOK) { - if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN) + int gotsig = 0; + + crecp = NULL; + while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY))) { - char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL); - gotsig = 1; - - if (!dryrun && - add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crecp->ttd - now, &nameoffset, - T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata)) - anscount++; - } - } - /* Need to re-run original cache search */ - crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL; + if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN) + { + char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL); + gotsig = 1; + + if (!dryrun && + add_resource_record(header, limit, &trunc, nameoffset, &ansp, + crecp->ttd - now, &nameoffset, + T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata)) + anscount++; + } + } + /* Need to re-run original cache search */ + crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL; + } } #endif @@ -1918,42 +1919,45 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, crecp = save; } -#ifdef HAVE_DNSSEC - if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && - (crecp->flags & F_DNSSECOK) && - !(crecp->flags & F_NEG) && - sec_reqd && - option_bool(OPT_DNSSEC_VALID)) + /* If the client asked for DNSSEC and we can't provide RRSIGs, either + because we've not doing DNSSEC or the cached answer is signed by negative, + don't answer from the cache, forward instead. */ + if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd) { - /* We're returning validated data, need to return the RRSIG too. */ - - int sigtype = type; - /* The signature may have expired even though the data is still in cache, - forward instead of answering from cache if so. */ - int gotsig = 0; - - if (crecp->flags & F_CNAME) - sigtype = T_CNAME; - - crecp = NULL; - while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY))) + if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))) + crecp = NULL; +#ifdef HAVE_DNSSEC + else if (crecp->flags & F_DNSSECOK) { - if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN) + /* We're returning validated data, need to return the RRSIG too. */ + + int sigtype = type; + /* The signature may have expired even though the data is still in cache, + forward instead of answering from cache if so. */ + int gotsig = 0; + + if (crecp->flags & F_CNAME) + sigtype = T_CNAME; + + crecp = NULL; + while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY))) { - char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL); - gotsig = 1; - - if (!dryrun && - add_resource_record(header, limit, &trunc, nameoffset, &ansp, - crecp->ttd - now, &nameoffset, - T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata)) - anscount++; + if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN) + { + char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL); + gotsig = 1; + + if (!dryrun && + add_resource_record(header, limit, &trunc, nameoffset, &ansp, + crecp->ttd - now, &nameoffset, + T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata)) + anscount++; + } } + /* Need to re-run original cache search */ + crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL; } - /* Need to re-run original cache search */ - crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL; - } - + } #endif if (crecp) do