resolved: synthesize NODATA cache results when we find matching NSEC RRs
If we have a precisely matching NSEC RR for a name, we can use its type bit field to synthesize NODATA cache lookup results for all types not mentioned in there. This is useful for mDNS where NSEC RRs are used to indicate missing RRs for a specific type, but is beneficial in other cases too. To test this, consider these two lines: systemd-resolve-host -t NSEC nasa.gov systemd-resolve-host -t SRV nasa.gov The second line will not result in traffic as the first line already cached the NSEC field.
This commit is contained in:
parent
8730bccfc5
commit
37da893166
|
@ -521,8 +521,8 @@ fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceKey *k) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *cname_key = NULL;
|
||||
static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, DnsResourceKey *k) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *nsec_key = NULL, *cname_key = NULL;
|
||||
DnsCacheItem *i;
|
||||
const char *n;
|
||||
int r;
|
||||
|
@ -534,20 +534,29 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceK
|
|||
* much, after all this is just a cache */
|
||||
|
||||
i = hashmap_get(c->by_key, k);
|
||||
if (i || k->type == DNS_TYPE_CNAME || k->type == DNS_TYPE_DNAME)
|
||||
if (i || IN_SET(k->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME, DNS_TYPE_NSEC))
|
||||
return i;
|
||||
|
||||
n = DNS_RESOURCE_KEY_NAME(k);
|
||||
|
||||
/* Check if we have an NSEC record instead for the name. */
|
||||
nsec_key = dns_resource_key_new(k->class, DNS_TYPE_NSEC, n);
|
||||
if (!nsec_key)
|
||||
return NULL;
|
||||
|
||||
i = hashmap_get(c->by_key, nsec_key);
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
/* Check if we have a CNAME record instead */
|
||||
cname_key = dns_resource_key_new_cname(k);
|
||||
if (!cname_key)
|
||||
return NULL;
|
||||
|
||||
i = hashmap_get(c->by_key, cname_key);
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
/* OK, let's look for cached DNAME records. */
|
||||
n = DNS_RESOURCE_KEY_NAME(k);
|
||||
for (;;) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *dname_key = NULL;
|
||||
char label[DNS_LABEL_MAX];
|
||||
|
@ -578,6 +587,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
|
|||
int r;
|
||||
bool nxdomain = false;
|
||||
_cleanup_free_ char *key_str = NULL;
|
||||
DnsResourceRecord *nsec = NULL;
|
||||
DnsCacheItem *j, *first;
|
||||
|
||||
assert(c);
|
||||
|
@ -601,7 +611,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
|
|||
return 0;
|
||||
}
|
||||
|
||||
first = dns_cache_get_by_key_follow_cname(c, key);
|
||||
first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key);
|
||||
if (!first) {
|
||||
/* If one question cannot be answered we need to refresh */
|
||||
|
||||
|
@ -617,9 +627,11 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
|
|||
}
|
||||
|
||||
LIST_FOREACH(by_key, j, first) {
|
||||
if (j->rr)
|
||||
if (j->rr) {
|
||||
if (j->rr->key->type == DNS_TYPE_NSEC)
|
||||
nsec = j->rr;
|
||||
n++;
|
||||
else if (j->type == DNS_CACHE_NXDOMAIN)
|
||||
} else if (j->type == DNS_CACHE_NXDOMAIN)
|
||||
nxdomain = true;
|
||||
}
|
||||
|
||||
|
@ -627,9 +639,22 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (nsec && key->type != DNS_TYPE_NSEC) {
|
||||
log_debug("NSEC NODATA cache hit for %s", key_str);
|
||||
|
||||
/* We only found an NSEC record that matches our name.
|
||||
* If it says the type doesn't exit report
|
||||
* NODATA. Otherwise report a cache miss. */
|
||||
|
||||
*ret = NULL;
|
||||
*rcode = DNS_RCODE_SUCCESS;
|
||||
|
||||
return !bitmap_isset(nsec->nsec.types, key->type);
|
||||
}
|
||||
|
||||
log_debug("%s cache hit for %s",
|
||||
nxdomain ? "NXDOMAIN" :
|
||||
n > 0 ? "Positive" : "NODATA",
|
||||
n > 0 ? "Positive" :
|
||||
nxdomain ? "NXDOMAIN" : "NODATA",
|
||||
key_str);
|
||||
|
||||
if (n <= 0) {
|
||||
|
|
Loading…
Reference in a new issue