#include <dns/rdatasetiter.h>
#include <dns/rdataslab.h>
#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
#include <dns/stats.h>
#include <dns/time.h>
#include <dns/view.h>
statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
} else {
statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
- base = DNS_TYPEPAIR_COVERS(header->typepair);
+ base = DNS_TYPEPAIR_TYPE(header->typepair);
}
} else {
base = DNS_TYPEPAIR_TYPE(header->typepair);
rdataset->methods = &dns_rdataslab_rdatasetmethods;
rdataset->rdclass = qpdb->common.rdclass;
- rdataset->type = DNS_TYPEPAIR_TYPE(header->typepair);
- rdataset->covers = DNS_TYPEPAIR_COVERS(header->typepair);
+ if (NEGATIVE(header)) {
+ rdataset->type = dns_rdatatype_none;
+ rdataset->covers = DNS_TYPEPAIR_TYPE(header->typepair);
+ INSIST(DNS_TYPEPAIR_COVERS(header->typepair) ==
+ dns_rdatatype_none);
+ } else {
+ rdataset->type = DNS_TYPEPAIR_TYPE(header->typepair);
+ rdataset->covers = DNS_TYPEPAIR_COVERS(header->typepair);
+ }
rdataset->ttl = !ZEROTTL(header) ? header->expire - now : 0;
rdataset->trust = header->trust;
rdataset->resign = 0;
NODE_UNLOCK(nlock, &nlocktype);
}
- if (typepair == dns_rdatatype_dname) {
+ if (typepair == DNS_TYPEPAIR_VALUE(dns_rdatatype_dname, 0)) {
return DNS_R_DNAME;
}
return DNS_R_DELEGATION;
*/
static bool
related_headers(dns_slabheader_t *header, dns_typepair_t typepair,
- dns_typepair_t sigpair, dns_typepair_t negpair,
- dns_slabheader_t **foundp, dns_slabheader_t **foundsigp,
- bool *matchp) {
+ dns_typepair_t sigpair, dns_slabheader_t **foundp,
+ dns_slabheader_t **foundsigp, bool *matchp) {
if (!EXISTS(header) || ANCIENT(header)) {
return false;
}
- if (header->typepair == typepair) {
+ if (header->typepair == typepair && NEGATIVE(header)) {
+ /*
+ * In theory, the RRSIG(type) should not exist, but in reality,
+ * both the LRU and TTL based cleaning can delete one, but not
+ * the other. The INSIST below should be restored when we add
+ * a more strict synchronization between the type and its
+ * signature.
+ */
+ /* INSIST(*foundsigp == NULL); */
+ *foundp = header;
+ SET_IF_NOT_NULL(matchp, true);
+ return true;
+ } else if (header->typepair == typepair) {
*foundp = header;
SET_IF_NOT_NULL(matchp, true);
if (*foundsigp != NULL) {
return true;
}
} else if (header->typepair == sigpair) {
+ INSIST(!NEGATIVE(header));
*foundsigp = header;
SET_IF_NOT_NULL(matchp, true);
if (*foundp != NULL) {
return true;
}
- } else if (negpair != 0 && (header->typepair == RDATATYPE_NCACHEANY ||
- header->typepair == negpair))
- {
+ } else if (header->typepair == dns_typepair_any) {
+ INSIST(NEGATIVE(header));
*foundp = header;
*foundsigp = NULL;
SET_IF_NOT_NULL(matchp, true);
dns_typepair_t typepair = DNS_TYPEPAIR_VALUE(type, 0);
dns_typepair_t sigpair = DNS_SIGTYPE(type);
- return related_headers(header, typepair, sigpair, 0, foundp, foundsigp,
- NULL);
+ bool done = related_headers(header, typepair, sigpair, foundp,
+ foundsigp, NULL);
+ if (done && NEGATIVE(*foundp)) {
+ *foundp = NULL;
+ }
+
+ return done;
}
static isc_result_t
qpc_search_t *search = arg;
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
- dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
+ dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_result_t result;
isc_rwlock_t *nlock = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
continue;
}
- if (both_headers(header, dns_rdatatype_dname, &dname_header,
- &sigdname_header))
+ if (both_headers(header, dns_rdatatype_dname, &found,
+ &foundsig))
{
break;
}
}
- if (dname_header != NULL &&
- (!DNS_TRUST_PENDING(dname_header->trust) ||
- (search->options & DNS_DBFIND_PENDINGOK) != 0))
+ if (found != NULL && (!DNS_TRUST_PENDING(found->trust) ||
+ (search->options & DNS_DBFIND_PENDINGOK) != 0))
{
/*
* We increment the reference count on node to ensure that
qpcnode_acquire(search->qpdb, node, nlocktype,
isc_rwlocktype_none DNS__DB_FLARG_PASS);
search->zonecut = node;
- search->zonecut_header = dname_header;
- search->zonecut_sigheader = sigdname_header;
+ search->zonecut_header = found;
+ search->zonecut_sigheader = foundsig;
search->need_cleanup = true;
result = DNS_R_PARTIALMATCH;
} else {
continue;
}
- if (DNS_TYPEPAIR_TYPE(header->typepair) == 0) {
- continue;
- }
-
if (both_headers(header, dns_rdatatype_nsec, &found, &foundsig))
{
break;
}
}
+
if (found != NULL) {
if (nodep != NULL) {
qpcnode_acquire(search->qpdb, node, nlocktype,
dns_slabheader_t *found = NULL, *nsheader = NULL;
dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL;
dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL;
- dns_typepair_t typepair, sigpair, negpair;
+ dns_typepair_t typepair, sigpair;
qpc_search_t search;
qpc_search_init(&search, (qpcache_t *)db, options, __now);
*/
found = NULL;
foundsig = NULL;
- typepair = DNS_TYPEPAIR_VALUE(type, 0);
+ typepair = DNS_TYPEPAIR(type);
sigpair = DNS_SIGTYPE(type);
- negpair = DNS_TYPEPAIR_VALUE(0, type);
nsheader = NULL;
nsecheader = NULL;
nssig = NULL;
}
bool match = false;
- if (related_headers(header, typepair, sigpair, negpair, &found,
+ if (related_headers(header, typepair, sigpair, &found,
&foundsig, &match) &&
!MISSING_ANSWER(found, options))
{
continue;
}
+ if (NEGATIVE(header)) {
+ /*
+ * FIXME: As of now, we are not interested in
+ * the negative headers. This could be
+ * improved and we can bail out early if we've
+ * seen all the types below (positive or
+ * negative), but the code is not yet ready
+ * for this.
+ */
+ continue;
+ }
+
switch (header->typepair) {
case dns_rdatatype_cname:
if (!cname_ok) {
break;
default:
- if (typepair == dns_rdatatype_any &&
- DNS_TYPEPAIR_TYPE(header->typepair) != 0)
- {
+ if (typepair == dns_typepair_any) {
/* QTYPE==ANY, so any anwers will do */
found = header;
break;
result = DNS_R_NCACHENXRRSET;
}
} else if (typepair != found->typepair &&
- typepair != dns_rdatatype_any &&
- found->typepair == dns_rdatatype_cname)
+ typepair != dns_typepair_any &&
+ found->typepair == DNS_TYPEPAIR(dns_rdatatype_cname))
{
/*
* We weren't doing an ANY query and we found a CNAME instead
result = ISC_R_SUCCESS;
}
- if (typepair != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
+ if (typepair != dns_typepair_any || result == DNS_R_NCACHENXDOMAIN ||
result == DNS_R_NCACHENXRRSET)
{
bindrdatasets(search.qpdb, node, found, foundsig, search.now,
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- bool ns = (header->typepair == dns_rdatatype_ns ||
- header->typepair == DNS_SIGTYPE(dns_rdatatype_ns));
+ bool ns = header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
+ header->typepair == DNS_SIGTYPE(dns_rdatatype_ns);
if (check_stale_header(header, search, &header_prev)) {
if (ns) {
/*
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL;
- dns_typepair_t typepair, sigpair, negpair;
+ dns_typepair_t typepair, sigpair;
isc_result_t result = ISC_R_SUCCESS;
isc_rwlock_t *nlock = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
REQUIRE(version == NULL);
REQUIRE(type != dns_rdatatype_any);
- if (type == dns_rdatatype_none && covers == dns_rdatatype_none) {
+ if (type == dns_rdatatype_none) {
+ /* We can't search negative cache directly */
+ return ISC_R_NOTFOUND;
+ }
+ if (dns_rdatatype_issig(type) && covers == dns_rdatatype_none) {
return ISC_R_NOTFOUND;
}
NODE_RDLOCK(nlock, &nlocktype);
typepair = DNS_TYPEPAIR_VALUE(type, covers);
- negpair = DNS_TYPEPAIR_VALUE(0, type);
- sigpair = (covers == dns_rdatatype_none) ? DNS_SIGTYPE(type)
- : dns_rdatatype_none;
+ sigpair = !dns_rdatatype_issig(type) ? DNS_SIGTYPE(type)
+ : dns_typepair_none;
for (header = qpnode->data; header != NULL; header = header_next) {
header_next = header->next;
continue;
}
- if (related_headers(header, typepair, sigpair, negpair, &found,
+ if (related_headers(header, typepair, sigpair, &found,
&foundsig, NULL))
{
break;
}
}
+
if (found != NULL) {
bindrdatasets(qpdb, qpnode, found, foundsig, search.now,
nlocktype, isc_rwlocktype_none, rdataset,
static bool
prio_header(dns_slabheader_t *header) {
- if (NEGATIVE(header) &&
- prio_type(DNS_TYPEPAIR_COVERS(header->typepair)))
- {
- return true;
- }
-
return prio_type(header->typepair);
}
dns_slabheader_t *topheader = NULL, *topheader_prev = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL;
dns_slabheader_t *prioheader = NULL, *expireheader = NULL;
- dns_typepair_t negpair = 0;
dns_trust_t trust;
uint32_t ntypes = 0;
+ dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
+ dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->typepair);
+ dns_typepair_t sigpair = !dns_rdatatype_issig(rdtype)
+ ? DNS_SIGTYPE(rdtype)
+ : dns_typepair_none;
+
+ REQUIRE(rdtype != dns_rdatatype_none);
+ if (dns_rdatatype_issig(rdtype)) {
+ /* signature must be positive, and cover a type */
+ REQUIRE(!NEGATIVE(newheader));
+ REQUIRE(covers != dns_rdatatype_none);
+ } else {
+ /* otherwise, it must cover nothing */
+ REQUIRE(covers == dns_rdatatype_none);
+ }
+ /* positive header can't be ANY */
+ REQUIRE(rdtype != dns_rdatatype_any || NEGATIVE(newheader));
if ((options & DNS_DBADD_FORCE) != 0) {
trust = dns_trust_ultimate;
}
if (EXISTS(newheader)) {
- dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
- dns_rdatatype_t covers =
- DNS_TYPEPAIR_COVERS(newheader->typepair);
- dns_typepair_t sigpair = DNS_SIGTYPE(covers);
if (NEGATIVE(newheader)) {
/*
* We're adding a negative cache entry.
*/
- if (covers == dns_rdatatype_any) {
+ if (rdtype == dns_rdatatype_any) {
/*
* If we're adding an negative cache entry
* which covers all types (NXDOMAIN,
break;
}
}
- negpair = DNS_TYPEPAIR_VALUE(covers,
- dns_rdatatype_none);
} else {
/*
* We're adding something that isn't a
- * negative cache entry. Look for an extant
- * non-ancient NXDOMAIN/NODATA(QTYPE=ANY) negative
- * cache entry. If we're adding an RRSIG, also
- * check for an extant non-ancient NODATA ncache
- * entry which covers the same type as the RRSIG.
+ * negative cache entry.
*/
for (topheader = qpnode->data; topheader != NULL;
topheader = topheader->next)
{
- if ((topheader->typepair ==
- RDATATYPE_NCACHEANY) ||
- (newheader->typepair == sigpair &&
- topheader->typepair ==
- DNS_TYPEPAIR_VALUE(
- dns_rdatatype_none,
- covers)))
+ /*
+ * Look for any existing negative cache
+ * entries.
+ */
+ if (!NEGATIVE(topheader)) {
+ continue;
+ }
+
+ /*
+ * If we find a cached NXDOMAIN, don't
+ * cache anything else.
+ */
+ if (topheader->typepair == dns_typepair_any) {
+ break;
+ }
+
+ /*
+ * Don't cache an RRSIG if it cover a type
+ * for which we have a cached NODATA record.
+ */
+ if (newheader->typepair == sigpair &&
+ DNS_TYPEPAIR_TYPE(topheader->typepair) ==
+ covers)
{
break;
}
topheader = NULL;
goto find_header;
}
- negpair = DNS_TYPEPAIR_VALUE(0, rdtype);
}
}
prioheader = topheader;
}
- if (topheader->typepair == newheader->typepair ||
- topheader->typepair == negpair)
- {
+ if (topheader->typepair == newheader->typepair) {
break;
}
topheader_prev = topheader;
* normally further down.
*/
if (ACTIVE(header, now) &&
- header->typepair == dns_rdatatype_ns && EXISTS(header) &&
- EXISTS(newheader) && header->trust >= newheader->trust &&
+ header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
+ EXISTS(header) && EXISTS(newheader) &&
+ header->trust >= newheader->trust &&
dns_rdataslab_equalx(header, newheader,
qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(header->typepair)))
* ensures the delegations that are withdrawn are honoured.
*/
if (ACTIVE(header, now) &&
- header->typepair == dns_rdatatype_ns && EXISTS(header) &&
- EXISTS(newheader) && header->trust <= newheader->trust)
+ header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
+ EXISTS(header) && EXISTS(newheader) &&
+ header->trust <= newheader->trust)
{
if (newheader->expire > header->expire) {
newheader->expire = header->expire;
}
if (ACTIVE(header, now) &&
(options & DNS_DBADD_PREFETCH) == 0 &&
- (header->typepair == dns_rdatatype_a ||
- header->typepair == dns_rdatatype_aaaa ||
- header->typepair == dns_rdatatype_ds ||
+ (header->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
+ header->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
+ header->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
header->typepair == DNS_SIGTYPE(dns_rdatatype_ds)) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust &&
dns_slabheader_t *newheader = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL;
+ uint16_t attributes = DNS_SLABHEADERATTR_NONEXISTENT;
REQUIRE(VALID_QPDB(qpdb));
REQUIRE(version == NULL);
+ /* Positive ANY type can't be in the cache. */
if (type == dns_rdatatype_any) {
return ISC_R_NOTIMPLEMENTED;
}
+
+ /* Convert the negative type into positive type. */
+ if (type == dns_rdatatype_none && covers != dns_rdatatype_none) {
+ type = covers;
+ covers = dns_rdatatype_none;
+ attributes |= DNS_SLABHEADERATTR_NEGATIVE;
+ }
+
+ /* RRSIG must have covered type */
if (type == dns_rdatatype_rrsig && covers == dns_rdatatype_none) {
return ISC_R_NOTIMPLEMENTED;
}
newheader = dns_slabheader_new(db, node);
newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers);
setttl(newheader, 0);
- atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT);
+ atomic_init(&newheader->attributes, attributes);
nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_WRLOCK(nlock, &nlocktype);