mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-20 02:38:32 +00:00
More DNSSEC caching logic, and avoid repeated validation of DS/DNSKEY
This commit is contained in:
@@ -141,10 +141,18 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
|
{
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (daemon->cachesize <CACHESIZ && option_bool(OPT_DNSSEC_VALID))
|
if (!daemon->dnskeys)
|
||||||
die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
|
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
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_TFTP
|
#ifndef HAVE_TFTP
|
||||||
if (option_bool(OPT_TFTP))
|
if (option_bool(OPT_TFTP))
|
||||||
|
|||||||
@@ -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.
|
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,
|
Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
|
||||||
return it to the original requestor. */
|
return it to the original requestor. */
|
||||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
while (forward->dependent)
|
||||||
{
|
{
|
||||||
while (forward->dependent)
|
struct frec *prev = forward->dependent;
|
||||||
{
|
free_frec(forward);
|
||||||
struct frec *prev;
|
forward = prev;
|
||||||
|
forward->blocking_query = NULL; /* already gone */
|
||||||
|
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||||
|
n = forward->stash_len;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All DNSKEY and DS records done and in cache, now finally validate original
|
|
||||||
answer, provided last DNSKEY is OK. */
|
|
||||||
if (status == STAT_SECURE)
|
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"));
|
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||||
status = STAT_INSECURE;
|
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)
|
if (status == STAT_TRUNCATED)
|
||||||
header->hb3 |= HB3_TC;
|
header->hb3 |= HB3_TC;
|
||||||
else
|
else
|
||||||
log_query(F_KEYTAG | F_SECSTAT, "result", NULL,
|
log_query(F_KEYTAG | F_SECSTAT, "result", NULL,
|
||||||
status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||||
|
|||||||
104
src/rfc1035.c
104
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)))
|
else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DNSSEC
|
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
|
|
||||||
(crecp->flags & F_DNSSECOK) &&
|
|
||||||
!(crecp->flags & F_NEG) &&
|
|
||||||
sec_reqd &&
|
|
||||||
option_bool(OPT_DNSSEC_VALID))
|
|
||||||
{
|
{
|
||||||
int gotsig = 0;
|
if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
|
||||||
|
crecp = NULL;
|
||||||
crecp = NULL;
|
#ifdef HAVE_DNSSEC
|
||||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
|
else if (crecp->flags & F_DNSSECOK)
|
||||||
{
|
{
|
||||||
if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
|
int gotsig = 0;
|
||||||
{
|
|
||||||
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
|
|
||||||
gotsig = 1;
|
|
||||||
|
|
||||||
if (!dryrun &&
|
crecp = NULL;
|
||||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
|
||||||
crecp->ttd - now, &nameoffset,
|
{
|
||||||
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
|
if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
|
||||||
anscount++;
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
/* Need to re-run original cache search */
|
|
||||||
crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1918,42 +1919,45 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
crecp = save;
|
crecp = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
/* If the client asked for DNSSEC and we can't provide RRSIGs, either
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
|
because we've not doing DNSSEC or the cached answer is signed by negative,
|
||||||
(crecp->flags & F_DNSSECOK) &&
|
don't answer from the cache, forward instead. */
|
||||||
!(crecp->flags & F_NEG) &&
|
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
|
||||||
sec_reqd &&
|
|
||||||
option_bool(OPT_DNSSEC_VALID))
|
|
||||||
{
|
{
|
||||||
/* We're returning validated data, need to return the RRSIG too. */
|
if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
|
||||||
|
crecp = NULL;
|
||||||
int sigtype = type;
|
#ifdef HAVE_DNSSEC
|
||||||
/* The signature may have expired even though the data is still in cache,
|
else if (crecp->flags & F_DNSSECOK)
|
||||||
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 (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);
|
if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
|
||||||
gotsig = 1;
|
{
|
||||||
|
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
|
||||||
|
gotsig = 1;
|
||||||
|
|
||||||
if (!dryrun &&
|
if (!dryrun &&
|
||||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||||
crecp->ttd - now, &nameoffset,
|
crecp->ttd - now, &nameoffset,
|
||||||
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
|
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
|
||||||
anscount++;
|
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
|
#endif
|
||||||
if (crecp)
|
if (crecp)
|
||||||
do
|
do
|
||||||
|
|||||||
Reference in New Issue
Block a user