diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh index fc05635e31..2e089fa371 100755 --- a/bin/tests/system/resolver/tests.sh +++ b/bin/tests/system/resolver/tests.sh @@ -596,18 +596,18 @@ n=$((n + 1)) echo_i "check prefetch qtype * (${n})" ret=0 dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.1.${n} || ret=1 -ttl1=$(awk '/"A" "short" "ttl"/ { print $2 - 3 }' dig.out.1.${n}) +ttl1=$(awk '/^fetchall.tld/ { print $2 - 3; exit }' dig.out.1.${n}) # sleep so we are in prefetch range sleep "${ttl1:-0}" # trigger prefetch dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.2.${n} || ret=1 -ttl2=$(awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}) +ttl2=$(awk '/^fetchall.tld/ { print $2; exit }' dig.out.2.${n}) sleep 1 # check that prefetch occurred; -# note that only one record is prefetched, which is the AAAA record in this case, +# note that only the first record is prefetched, # because of the order of the records in the cache dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.3.${n} || ret=1 -ttl3=$(awk '/::1/ { print $2 }' dig.out.3.${n}) +ttl3=$(awk '/^fetchall.tld/ { print $2; exit }' dig.out.3.${n}) test "${ttl3:-0}" -gt "${ttl2:-1}" || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index b35e101b01..9670671d1e 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -990,6 +990,8 @@ prio_type(rbtdb_rdatatype_t type) { case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_soa): case dns_rdatatype_a: case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_a): + case dns_rdatatype_mx: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_mx): case dns_rdatatype_aaaa: case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_aaaa): case dns_rdatatype_nsec: @@ -1002,6 +1004,22 @@ prio_type(rbtdb_rdatatype_t type) { case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ds): case dns_rdatatype_cname: case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname): + case dns_rdatatype_dname: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname): + case dns_rdatatype_svcb: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_svcb): + case dns_rdatatype_https: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_https): + case dns_rdatatype_dnskey: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dnskey): + case dns_rdatatype_srv: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_srv): + case dns_rdatatype_txt: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_txt): + case dns_rdatatype_ptr: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ptr): + case dns_rdatatype_naptr: + case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_naptr): return (true); } return (false); @@ -6244,6 +6262,26 @@ update_recordsandxfrsize(bool add, rbtdb_version_t *rbtversion, #define DNS_RBTDB_MAX_RTYPES 100 #endif /* DNS_RBTDB_MAX_RTYPES */ +static bool +overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) { + UNUSED(rbtdb); + + if (DNS_RBTDB_MAX_RTYPES == 0) { + return (false); + } + + return (ntypes >= DNS_RBTDB_MAX_RTYPES); +} + +static bool +prio_header(rdatasetheader_t *header) { + if (NEGATIVE(header) && prio_type(RBTDB_RDATATYPE_EXT(header->type))) { + return (true); + } + + return (prio_type(header->type)); +} + /* * write lock on rbtnode must be held. */ @@ -6255,7 +6293,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, rbtdb_changed_t *changed = NULL; rdatasetheader_t *topheader = NULL, *topheader_prev = NULL; rdatasetheader_t *header = NULL, *sigheader = NULL; - rdatasetheader_t *prioheader = NULL; + rdatasetheader_t *prioheader = NULL, *expireheader = NULL; unsigned char *merged = NULL; isc_result_t result; bool header_nx; @@ -6265,7 +6303,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, rbtdb_rdatatype_t negtype, sigtype; dns_trust_t trust; int idx; - uint32_t ntypes; + uint32_t ntypes = 0; /* * Add an rdatasetheader_t to a node. @@ -6330,7 +6368,6 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, set_ttl(rbtdb, topheader, 0); mark_header_ancient(rbtdb, topheader); } - ntypes = 0; goto find_header; } /* @@ -6342,6 +6379,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, { if (topheader->type == sigtype) { sigheader = topheader; + break; } } negtype = RBTDB_RDATATYPE_VALUE(covers, 0); @@ -6354,11 +6392,9 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, * check for an extant non-ancient NODATA ncache * entry which covers the same type as the RRSIG. */ - ntypes = 0; for (topheader = rbtnode->data; topheader != NULL; topheader = topheader->next) { - ntypes++; if ((topheader->type == RBTDB_RDATATYPE_NCACHEANY) || (newheader->type == sigtype && @@ -6403,12 +6439,16 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, } } - ntypes = 0; for (topheader = rbtnode->data; topheader != NULL; topheader = topheader->next) { - ntypes++; - if (prio_type(topheader->type)) { + if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) { + ++ntypes; + expireheader = topheader; + } else if (!IS_CACHE(rbtdb)) { + ++ntypes; + } + if (prio_header(topheader)) { prioheader = topheader; } if (topheader->type == newheader->type || @@ -6765,8 +6805,7 @@ find_header: /* * No rdatasets of the given type exist at the node. */ - - if (ntypes > DNS_RBTDB_MAX_RTYPES) { + if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { free_rdataset(rbtdb, rbtdb->common.mctx, newheader); return (ISC_R_QUOTA); @@ -6774,7 +6813,7 @@ find_header: newheader->down = NULL; - if (prio_type(newheader->type)) { + if (prio_header(newheader)) { /* This is a priority type, prepend it */ newheader->next = rbtnode->data; rbtnode->data = newheader; @@ -6787,6 +6826,31 @@ find_header: newheader->next = rbtnode->data; rbtnode->data = newheader; } + + if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { + if (expireheader == NULL) { + expireheader = newheader; + } + if (NEGATIVE(newheader) && + !prio_header(newheader)) + { + /* + * Add the new non-priority negative + * header to the database only + * temporarily. + */ + expireheader = newheader; + } + + set_ttl(rbtdb, expireheader, 0); + mark_header_ancient(rbtdb, expireheader); + /* + * FIXME: In theory, we should mark the RRSIG + * and the header at the same time, but there is + * no direct link between those two header, so + * we would have to check the whole list again. + */ + } } }