mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
resolved: cache - cache what we can of negative redirect chains
When a NXDATA or a NODATA response is received for an alias it may include CNAME records from the redirect chain. We should cache the response for each of these names to avoid needless roundtrips in the future. It is not sufficient to do the negative caching only for the canonical name, as the included redirection chain is not guaranteed to be complete. In fact, only the final CNAME record from the chain is guaranteed to be included. We take care not to cache entries that redirects outside the current zone, as the SOA will then not be valid.
This commit is contained in:
parent
5643c00afe
commit
5eefe544ef
@ -149,6 +149,19 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa) {
|
||||
if (soa->class != DNS_CLASS_IN)
|
||||
return 0;
|
||||
|
||||
if (soa->type != DNS_TYPE_SOA)
|
||||
return 0;
|
||||
|
||||
if (!dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret) {
|
||||
unsigned i;
|
||||
|
||||
@ -164,13 +177,7 @@ int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **r
|
||||
|
||||
for (i = 0; i < a->n_rrs; i++) {
|
||||
|
||||
if (a->items[i].rr->key->class != DNS_CLASS_IN)
|
||||
continue;
|
||||
|
||||
if (a->items[i].rr->key->type != DNS_TYPE_SOA)
|
||||
continue;
|
||||
|
||||
if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->items[i].rr->key))) {
|
||||
if (dns_answer_match_soa(key, a->items[i].rr->key)) {
|
||||
*ret = a->items[i].rr;
|
||||
return 1;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a);
|
||||
int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex);
|
||||
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl);
|
||||
int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key);
|
||||
int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa);
|
||||
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret);
|
||||
|
||||
DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b);
|
||||
|
@ -474,6 +474,31 @@ int dns_cache_put(
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
/* Also, if the requested key is an alias, the negative response should
|
||||
be cached for each name in the redirect chain. Any CNAME record in
|
||||
the response is from the redirection chain, though only the final one
|
||||
is guaranteed to be included. This means that we cannot verify the
|
||||
chain and that we need to cache them all as it may be incomplete. */
|
||||
for (i = 0; i < answer->n_rrs; i++) {
|
||||
DnsResourceRecord *answer_rr = answer->items[i].rr;
|
||||
|
||||
if (answer_rr->key->type == DNS_TYPE_CNAME) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *canonical_key = NULL;
|
||||
|
||||
canonical_key = dns_resource_key_new_redirect(key, answer_rr);
|
||||
if (!canonical_key)
|
||||
goto fail;
|
||||
|
||||
/* Let's not add negative cache entries for records outside the current zone. */
|
||||
if (!dns_answer_match_soa(canonical_key, soa->key))
|
||||
continue;
|
||||
|
||||
r = dns_cache_put_negative(c, canonical_key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
r = dns_cache_put_negative(c, key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
Loading…
Reference in New Issue
Block a user