for (size_t i = 0; i < ARRAY_SIZE(item); i++) {
size_t len = isc_random_uniform(100) + 16;
- item[i].len = len;
- for (size_t off = 0; off < len; off++) {
+ item[i].len = len + 1;
+ item[i].key[0] = 0;
+ for (size_t off = 1; off < len; off++) {
item[i].key[off] = random_byte();
}
- memmove(item[i].ascii, item[i].key, len);
- qp_test_keytoascii(item[i].ascii, len);
+ memmove(item[i].ascii, item[i].key, item[i].len);
+ qp_test_keytoascii(item[i].ascii, item[i].len);
}
return 0;
dns_name_t *namein, *nameout, *namecmp;
isc_buffer_t buf;
dns_qpkey_t key, cmp;
+ uint8_t denial;
namein = dns_fixedname_initname(&fixedin);
nameout = dns_fixedname_initname(&fixedout);
CHECK(dns_name_fromwire(namein, &buf, DNS_DECOMPRESS_NEVER, NULL));
/* verify round-trip conversion of first name */
- size_t keylen = dns_qpkey_fromname(key, namein);
- dns_qpkey_toname(key, keylen, nameout);
+ size_t keylen = dns_qpkey_fromname(key, namein, 0);
+ dns_qpkey_toname(key, keylen, nameout, &denial);
assert(dns_name_equal(namein, nameout));
+ assert(denial == 0);
/* is there a second name? */
CHECK(dns_name_fromwire(namecmp, &buf, DNS_DECOMPRESS_NEVER, NULL));
- size_t cmplen = dns_qpkey_fromname(cmp, namecmp);
+ size_t cmplen = dns_qpkey_fromname(cmp, namecmp, 0);
size_t len = ISC_MIN(keylen, cmplen);
int namerel = dns_name_compare(namein, namecmp);
assert((namerel < 0) == (keyrel < 0));
assert((namerel == 0) == (keyrel == 0));
assert((namerel > 0) == (keyrel > 0));
+ assert(denial == 0);
return 0;
}
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns_forwarders_t *fwd = pval;
- return dns_qpkey_fromname(key, &fwd->name);
+ return dns_qpkey_fromname(key, &fwd->name, 0);
}
static void
* exists in a specal tree for NSEC or NSEC3.
*/
enum {
- DNS_DB_NSEC_NORMAL = 0, /* in main tree */
- DNS_DB_NSEC_HAS_NSEC = 1, /* also has node in nsec tree */
- DNS_DB_NSEC_NSEC = 2, /* in nsec tree */
- DNS_DB_NSEC_NSEC3 = 3 /* in nsec3 tree */
+ DNS_DB_NSEC_NORMAL = 0, /* in main tree */
+ DNS_DB_NSEC_NSEC = 2, /* in nsec tree */
+ DNS_DB_NSEC_NSEC3 = 3 /* in nsec3 tree */
};
/*@{*/
* A domain name can be up to 255 bytes. When converted to a key, each
* character in the name corresponds to one byte in the key if it is a
* common hostname character; otherwise unusual characters are escaped,
- * using two bytes in the key. So we allow keys to be up to 512 bytes.
- * (The actual max is (255 - 5) * 2 + 6 == 506)
+ * using two bytes in the key. Because the maximum label length is 63
+ * characters, the actual max is (255 - 5) * 2 + 6 == 506. Then, we need
+ * one more byte to prepend the denial of existence value.
+ *
+ * Note: this gives us 5 bytes available space to store more data.
*/
#define DNS_QP_MAXKEY 512
*/
size_t
-dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name);
+dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name, uint8_t denial);
/*%<
* Convert a DNS name into a trie lookup key.
*
+ * If 'denial' is DNS_DB_NSEC_NORMAL (0), convert the name for a NSEC lookup.
+ * If 'denial' is DNS_DB_NSEC_NSEC, convert the name for a NSEC lookup.
+ * If 'denial' is DNS_DB_NSEC_NSEC3, convert the name for a NSEC3 lookup.
+ *
* Requires:
* \li `name` is a pointer to a valid `dns_name_t`
*
*/
void
-dns_qpkey_toname(const dns_qpkey_t key, size_t keylen, dns_name_t *name);
+dns_qpkey_toname(const dns_qpkey_t key, size_t keylen, dns_name_t *name,
+ uint8_t *denial);
/*%<
* Convert a trie lookup key back into a DNS name.
*
+ * 'denial' stores whether the key is for a normal name, or denial of existence.
+ *
* Requires:
* \li `name` is a pointer to a valid `dns_name_t`
* \li `name->buffer` is not NULL
*/
isc_result_t
-dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, void **pval_r,
- uint32_t *ival_r);
+dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, uint8_t denial,
+ void **pval_r, uint32_t *ival_r);
/*%<
- * Find a leaf in a qp-trie that matches the given DNS name
+ * Find a leaf in a qp-trie that matches the given DNS name, and denial value.
*
* The leaf values are assigned to whichever of `*pval_r` and `*ival_r`
* are not null, unless the return value is ISC_R_NOTFOUND.
* \li ISC_R_NOTFOUND if no match was found
*/
+isc_result_t
+dns_qp_lookup2(dns_qpreadable_t qpr, const dns_name_t *name, uint8_t denial,
+ dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
+ void **pval_r, uint32_t *ival_r);
+/*%<
+ * The same as 'dns_qp_lookup', but with the possibility to set a denial value,
+ * either DNS_DB_NSEC_NORMAL (or 0, which is the equivalent of 'dns_qp_lookup'),
+ * DNS_DB_NSEC_NSEC, OR DNS_DB_NSEC3.
+ */
+
isc_result_t
dns_qp_insert(dns_qp_t *qp, void *pval, uint32_t ival);
/*%<
*/
isc_result_t
-dns_qp_deletename(dns_qp_t *qp, const dns_name_t *name, void **pval_r,
- uint32_t *ival_r);
+dns_qp_deletename(dns_qp_t *qp, const dns_name_t *name, uint8_t denial,
+ void **pval_r, uint32_t *ival_r);
/*%<
- * Delete a leaf from a qp-trie that matches the given DNS name
+ * Delete a leaf from a qp-trie that matches the given DNS name, and denial
+ * value.
*
* The leaf values are assigned to whichever of `*pval_r` and `*ival_r`
* are not null, unless the return value is ISC_R_NOTFOUND.
}
}
- result = dns_qp_deletename(qp, &knode->name, &pval, NULL);
+ result = dns_qp_deletename(qp, &knode->name, 0, &pval, NULL);
INSIST(result == ISC_R_SUCCESS);
INSIST(pval == knode);
dns_qpmulti_write(keytable->table, &qp);
- result = dns_qp_getname(qp, keyname, &pval, NULL);
+ result = dns_qp_getname(qp, keyname, 0, &pval, NULL);
if (result != ISC_R_SUCCESS) {
/*
* There was no match for "keyname" in "keytable" yet, so one
REQUIRE(keyname != NULL);
dns_qpmulti_write(keytable->table, &qp);
- result = dns_qp_deletename(qp, keyname, &pval, NULL);
+ result = dns_qp_deletename(qp, keyname, 0, &pval, NULL);
if (result == ISC_R_SUCCESS) {
dns_keynode_t *n = pval;
if (callback != NULL) {
REQUIRE(dnskey != NULL);
dns_qpmulti_write(keytable->table, &qp);
- result = dns_qp_getname(qp, keyname, &pval, NULL);
+ result = dns_qp_getname(qp, keyname, 0, &pval, NULL);
if (result != ISC_R_SUCCESS) {
goto finish;
}
REQUIRE(keynodep != NULL && *keynodep == NULL);
dns_qpmulti_query(keytable->table, &qpr);
- result = dns_qp_getname(&qpr, keyname, &pval, NULL);
+ result = dns_qp_getname(&qpr, keyname, 0, &pval, NULL);
if (result == ISC_R_SUCCESS) {
dns_keynode_t *knode = pval;
dns_keynode_attach(knode, keynodep);
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns_keynode_t *keynode = pval;
- return dns_qpkey_fromname(key, &keynode->name);
+ return dns_qpkey_fromname(key, &keynode->name, 0);
}
static void
case DNS_NAMETREE_COUNT:
new = newnode(nametree->mctx, name);
new->set = true;
- result = dns_qp_deletename(qp, name, (void **)&old, &count);
+ result = dns_qp_deletename(qp, name, 0, (void **)&old, &count);
if (result == ISC_R_SUCCESS) {
count += 1;
}
break;
case DNS_NAMETREE_BITS:
- result = dns_qp_getname(qp, name, (void **)&old, NULL);
+ result = dns_qp_getname(qp, name, 0, (void **)&old, NULL);
if (result == ISC_R_SUCCESS && matchbit(old->bits, value)) {
goto out;
}
new->bits = isc_mem_cget(nametree->mctx, size, sizeof(char));
if (result == ISC_R_SUCCESS) {
memmove(new->bits, old->bits, old->bits[0]);
- result = dns_qp_deletename(qp, name, NULL, NULL);
+ result = dns_qp_deletename(qp, name, 0, NULL, NULL);
INSIST(result == ISC_R_SUCCESS);
}
REQUIRE(name != NULL);
dns_qpmulti_write(nametree->table, &qp);
- result = dns_qp_deletename(qp, name, (void **)&old, &count);
+ result = dns_qp_deletename(qp, name, 0, (void **)&old, &count);
switch (nametree->type) {
case DNS_NAMETREE_BOOL:
case DNS_NAMETREE_BITS:
REQUIRE(ntnodep != NULL && *ntnodep == NULL);
dns_qpmulti_query(nametree->table, &qpr);
- result = dns_qp_getname(&qpr, name, (void **)&node, NULL);
+ result = dns_qp_getname(&qpr, name, 0, (void **)&node, NULL);
if (result == ISC_R_SUCCESS) {
dns_ntnode_attach(node, ntnodep);
}
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns_ntnode_t *ntnode = pval;
- return dns_qpkey_fromname(key, &ntnode->name);
+ return dns_qpkey_fromname(key, &ntnode->name, 0);
}
static void
result = dns_qp_insert(qp, nta, 0);
switch (result) {
case ISC_R_EXISTS:
- result = dns_qp_getname(qp, &nta->name, &pval, NULL);
+ result = dns_qp_getname(qp, &nta->name, 0, &pval, NULL);
if (result == ISC_R_SUCCESS) {
/*
* an NTA already existed: throw away the
REQUIRE(name != NULL);
dns_qpmulti_write(ntatable->table, &qp);
- result = dns_qp_deletename(qp, name, &pval, NULL);
+ result = dns_qp_deletename(qp, name, 0, &pval, NULL);
if (result == ISC_R_SUCCESS) {
dns__nta_t *n = pval;
dns__nta_shutdown(n);
RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
dns_qpmulti_write(ntatable->table, &qp);
- result = dns_qp_getname(qp, &nta->name, &pval, NULL);
+ result = dns_qp_getname(qp, &nta->name, 0, &pval, NULL);
if (result == ISC_R_SUCCESS &&
((dns__nta_t *)pval)->expiry == nta->expiry && !nta->shuttingdown)
{
dns_name_format(&nta->name, nb, sizeof(nb));
isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_NTA,
ISC_LOG_INFO, "deleting expired NTA at %s", nb);
- dns_qp_deletename(qp, &nta->name, NULL, NULL);
+ dns_qp_deletename(qp, &nta->name, 0, NULL, NULL);
dns__nta_shutdown(nta);
dns__nta_unref(nta);
}
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns__nta_t *nta = pval;
- return dns_qpkey_fromname(key, &nta->name);
+ return dns_qpkey_fromname(key, &nta->name, 0);
}
static void
#include <isc/urcu.h>
#include <isc/util.h>
+#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/qp.h>
* converting DNS names to trie keys
*/
+/*
+ * An offset for the denial value.
+ */
+#define DENIAL_OFFSET 48
+
/*
* Number of distinct byte values, i.e. 256
*/
* dot in a zone file).
*/
size_t
-dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name) {
+dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name, uint8_t denial) {
REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
+ REQUIRE(denial <= DNS_DB_NSEC_NSEC3);
dns_offsets_t offsets;
size_t labels = dns_name_offsets(name, offsets);
+ size_t len = 0;
+ /* denial? */
+ key[len++] = dns_qp_bits_for_byte[denial + DENIAL_OFFSET];
+ /* name */
if (labels == 0) {
- key[0] = SHIFT_NOBYTE;
- return 0;
+ key[len] = SHIFT_NOBYTE;
+ return len;
}
- size_t len = 0;
size_t label = labels;
while (label-- > 0) {
const uint8_t *ldata = name->ndata + offsets[label];
}
void
-dns_qpkey_toname(const dns_qpkey_t key, size_t keylen, dns_name_t *name) {
+dns_qpkey_toname(const dns_qpkey_t key, size_t keylen, dns_name_t *name,
+ uint8_t *denial) {
size_t locs[DNS_NAME_MAXLABELS];
size_t loc = 0;
size_t offset;
REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
REQUIRE(name->buffer != NULL);
+ REQUIRE(keylen > 0);
dns_name_reset(name);
- if (keylen == 0) {
+ SET_IF_NOT_NULL(denial, dns_qp_byte_for_bit[key[0]] - DENIAL_OFFSET);
+
+ if (keylen == 1) {
return;
}
/* Scan the key looking for label boundaries */
- for (offset = 0; offset <= keylen; offset++) {
+ for (offset = 1; offset <= keylen; offset++) {
INSIST(key[offset] >= SHIFT_NOBYTE &&
key[offset] < SHIFT_OFFSET);
INSIST(loc < DNS_NAME_MAXLABELS);
goto scanned;
}
locs[loc++] = offset + 1;
- } else if (offset == 0) {
+ } else if (offset == 1) {
/* This happens for a relative name */
locs[loc++] = offset;
}
}
/* Add a root label for absolute names */
- if (key[0] == SHIFT_NOBYTE) {
+ if (key[1] == SHIFT_NOBYTE) {
name->attributes.absolute = true;
isc_buffer_putuint8(name->buffer, 0);
name->length++;
}
isc_result_t
-dns_qp_deletename(dns_qp_t *qp, const dns_name_t *name, void **pval_r,
- uint32_t *ival_r) {
+dns_qp_deletename(dns_qp_t *qp, const dns_name_t *name, uint8_t denial,
+ void **pval_r, uint32_t *ival_r) {
dns_qpkey_t key;
- size_t keylen = dns_qpkey_fromname(key, name);
+ size_t keylen = dns_qpkey_fromname(key, name, denial);
return dns_qp_deletekey(qp, key, keylen, pval_r, ival_r);
}
dns_name_reset(name);
len = leaf_qpkey(qp, node, key);
- dns_qpkey_toname(key, len, name);
+ dns_qpkey_toname(key, len, name, NULL);
}
void
}
isc_result_t
-dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, void **pval_r,
- uint32_t *ival_r) {
+dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, uint8_t denial,
+ void **pval_r, uint32_t *ival_r) {
dns_qpkey_t key;
- size_t keylen = dns_qpkey_fromname(key, name);
+ size_t keylen = dns_qpkey_fromname(key, name, denial);
return dns_qp_getkey(qpr, key, keylen, pval_r, ival_r);
}
}
isc_result_t
-dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
- dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
- void **pval_r, uint32_t *ival_r) {
+dns_qp_lookup2(dns_qpreadable_t qpr, const dns_name_t *name, uint8_t denial,
+ dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
+ void **pval_r, uint32_t *ival_r) {
dns_qpreader_t *qp = dns_qpreader(qpr);
dns_qpkey_t search, found;
size_t searchlen, foundlen;
REQUIRE(QP_VALID(qp));
REQUIRE(foundname == NULL || ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
- searchlen = dns_qpkey_fromname(search, name);
+ searchlen = dns_qpkey_fromname(search, name, denial);
if (chain == NULL) {
chain = &oc;
return ISC_R_NOTFOUND;
}
+isc_result_t
+dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
+ dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
+ void **pval_r, uint32_t *ival_r) {
+ return dns_qp_lookup2(qpr, name, 0, foundname, iter, chain, pval_r,
+ ival_r);
+}
+
/**********************************************************************/
uint8_t : 0;
unsigned int delegating : 1;
unsigned int nsec : 2; /*%< range is 0..3 */
+ unsigned int havensec : 1;
uint8_t : 0;
uint16_t locknum;
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
qpcnode_t *data = pval;
- return dns_qpkey_fromname(key, &data->name);
+ return dns_qpkey_fromname(key, &data->name, data->nsec);
}
static void
}
switch (node->nsec) {
- case DNS_DB_NSEC_HAS_NSEC:
- /*
- * Delete the corresponding node from the auxiliary NSEC
- * tree before deleting from the main tree.
- */
- result = dns_qp_deletename(qpdb->nsec, &node->name, NULL, NULL);
- if (result != ISC_R_SUCCESS) {
- isc_log_write(DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
- "delete_node(): "
- "dns_qp_deletename: %s",
- isc_result_totext(result));
- }
- /* FALLTHROUGH */
case DNS_DB_NSEC_NORMAL:
- result = dns_qp_deletename(qpdb->tree, &node->name, NULL, NULL);
+ if (node->havensec) {
+ /*
+ * Delete the corresponding node from the auxiliary NSEC
+ * tree before deleting from the main tree.
+ */
+ result = dns_qp_deletename(qpdb->nsec, &node->name,
+ DNS_DB_NSEC_NSEC, NULL,
+ NULL);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE,
+ ISC_LOG_WARNING,
+ "delete_node(): "
+ "dns_qp_deletename: %s",
+ isc_result_totext(result));
+ }
+ }
+ result = dns_qp_deletename(qpdb->tree, &node->name, node->nsec,
+ NULL, NULL);
break;
case DNS_DB_NSEC_NSEC:
- result = dns_qp_deletename(qpdb->nsec, &node->name, NULL, NULL);
+ result = dns_qp_deletename(qpdb->nsec, &node->name, node->nsec,
+ NULL, NULL);
break;
}
if (result != ISC_R_SUCCESS) {
/*
* Look for the node in the auxilary tree.
*/
- result = dns_qp_lookup(search->qpdb->nsec, name, NULL, &iter, NULL,
- (void **)&node, NULL);
+ result = dns_qp_lookup2(search->qpdb->nsec, name, DNS_DB_NSEC_NSEC,
+ NULL, &iter, NULL, (void **)&node, NULL);
if (result != DNS_R_PARTIALMATCH) {
return ISC_R_NOTFOUND;
}
* Lookup the predecessor in the main tree.
*/
node = NULL;
- result = dns_qp_getname(search->qpdb->tree, predecessor, (void **)&node,
- NULL);
+ result = dns_qp_getname(search->qpdb->tree, predecessor,
+ DNS_DB_NSEC_NORMAL, (void **)&node, NULL);
if (result != ISC_R_SUCCESS) {
return result;
}
qpcnode_t *node = NULL;
isc_result_t result;
isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
+ uint8_t dopt = DNS_DB_NSEC_NORMAL;
TREE_RDLOCK(&qpdb->tree_lock, &tlocktype);
- result = dns_qp_getname(qpdb->tree, name, (void **)&node, NULL);
+ result = dns_qp_getname(qpdb->tree, name, dopt, (void **)&node, NULL);
if (result != ISC_R_SUCCESS) {
if (!create) {
goto unlock;
* Try to upgrade the lock and if that fails unlock then relock.
*/
TREE_FORCEUPGRADE(&qpdb->tree_lock, &tlocktype);
- result = dns_qp_getname(qpdb->tree, name, (void **)&node, NULL);
+ result = dns_qp_getname(qpdb->tree, name, dopt, (void **)&node,
+ NULL);
if (result != ISC_R_SUCCESS) {
node = new_qpcnode(qpdb, name);
+ node->nsec = dopt;
result = dns_qp_insert(qpdb->tree, node, 0);
INSIST(result == ISC_R_SUCCESS);
qpcnode_unref(node);
*/
if (rdataset->type == dns_rdatatype_nsec) {
NODE_RDLOCK(nlock, &nlocktype);
- if (qpnode->nsec != DNS_DB_NSEC_HAS_NSEC) {
+ if (!qpnode->havensec) {
newnsec = true;
}
NODE_UNLOCK(nlock, &nlocktype);
expire_ttl_headers(qpdb, qpnode->locknum, &nlocktype, &tlocktype,
now DNS__DB_FLARG_PASS);
- if (newnsec && qpnode->nsec != DNS_DB_NSEC_HAS_NSEC) {
+ if (newnsec && !qpnode->havensec) {
qpcnode_t *nsecnode = NULL;
- result = dns_qp_getname(qpdb->nsec, name, (void **)&nsecnode,
- NULL);
+ result = dns_qp_getname(qpdb->nsec, name, DNS_DB_NSEC_NSEC,
+ (void **)&nsecnode, NULL);
if (result != ISC_R_SUCCESS) {
INSIST(nsecnode == NULL);
nsecnode = new_qpcnode(qpdb, name);
INSIST(result == ISC_R_SUCCESS);
qpcnode_detach(&nsecnode);
}
- qpnode->nsec = DNS_DB_NSEC_HAS_NSEC;
+ qpnode->havensec = true;
}
result = add(qpdb, qpnode, name, newheader, options, addedrdataset, now,
uint16_t locknum;
atomic_uint_fast8_t nsec;
+ atomic_bool havensec;
atomic_bool wild;
atomic_bool delegating;
atomic_bool dirty;
dns_qpmulti_write(qpdb->tree, &qp);
qpdb->origin = new_qpznode(qpdb, &qpdb->common.origin);
+ qpdb->origin->nsec = DNS_DB_NSEC_NORMAL;
result = dns_qp_insert(qp, qpdb->origin, 0);
INSIST(result == ISC_R_SUCCESS);
- qpdb->origin->nsec = DNS_DB_NSEC_NORMAL;
dns_qpmulti_commit(qpdb->tree, &qp);
/*
qpznode_t *node = NULL, *nsecnode = NULL;
if (type == dns_rdatatype_nsec3 || covers == dns_rdatatype_nsec3) {
- result = dns_qp_getname(loadctx->nsec3, name, (void **)&node,
- NULL);
+ result = dns_qp_getname(loadctx->nsec3, name, DNS_DB_NSEC_NSEC3,
+ (void **)&node, NULL);
if (result == ISC_R_SUCCESS) {
*nodep = node;
} else {
node = new_qpznode(qpdb, name);
+ node->nsec = DNS_DB_NSEC_NSEC3;
result = dns_qp_insert(loadctx->nsec3, node, 0);
INSIST(result == ISC_R_SUCCESS);
- node->nsec = DNS_DB_NSEC_NSEC3;
*nodep = node;
qpznode_detach(&node);
}
return;
}
- result = dns_qp_getname(loadctx->tree, name, (void **)&node, NULL);
+ result = dns_qp_getname(loadctx->tree, name, DNS_DB_NSEC_NORMAL,
+ (void **)&node, NULL);
if (result == ISC_R_SUCCESS) {
- if (type == dns_rdatatype_nsec &&
- node->nsec == DNS_DB_NSEC_HAS_NSEC)
- {
+ if (type == dns_rdatatype_nsec && node->havensec) {
goto done;
}
} else {
INSIST(node == NULL);
node = new_qpznode(qpdb, name);
+ node->nsec = DNS_DB_NSEC_NORMAL;
result = dns_qp_insert(loadctx->tree, node, 0);
INSIST(result == ISC_R_SUCCESS);
qpznode_unref(node);
* node there, so we can just detach the new one we created and
* move on.
*/
- node->nsec = DNS_DB_NSEC_HAS_NSEC;
+ node->havensec = true;
nsecnode = new_qpznode(qpdb, name);
nsecnode->nsec = DNS_DB_NSEC_NSEC;
(void)dns_qp_insert(loadctx->nsec, nsecnode, 0);
}
static void
-wildcardmagic(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name) {
+wildcardmagic(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
+ uint8_t denial) {
isc_result_t result;
dns_name_t foundname;
unsigned int n;
dns_name_getlabelsequence(name, 1, n, &foundname);
/* insert an empty node, if needed, to hold the wildcard bit */
- result = dns_qp_getname(qp, &foundname, (void **)&node, NULL);
+ result = dns_qp_getname(qp, &foundname, denial, (void **)&node, NULL);
if (result != ISC_R_SUCCESS) {
INSIST(node == NULL);
node = new_qpznode(qpdb, &foundname);
+ node->nsec = denial;
result = dns_qp_insert(qp, node, 0);
INSIST(result == ISC_R_SUCCESS);
qpznode_unref(node);
}
static void
-addwildcards(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name) {
+addwildcards(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
+ uint8_t denial) {
dns_name_t foundname;
unsigned int n, l, i;
while (i < n) {
dns_name_getlabelsequence(name, n - i, i, &foundname);
if (dns_name_iswildcard(&foundname)) {
- wildcardmagic(qpdb, qp, &foundname);
+ wildcardmagic(qpdb, qp, &foundname, denial);
}
i++;
if (rdataset->type != dns_rdatatype_nsec3 &&
rdataset->covers != dns_rdatatype_nsec3)
{
- addwildcards(qpdb, loadctx->tree, name);
+ addwildcards(qpdb, loadctx->tree, name, DNS_DB_NSEC_NORMAL);
}
if (dns_name_iswildcard(name)) {
return DNS_R_INVALIDNSEC3;
}
- wildcardmagic(qpdb, loadctx->tree, name);
+ wildcardmagic(qpdb, loadctx->tree, name, DNS_DB_NSEC_NORMAL);
}
loading_addnode(loadctx, name, rdataset->type, rdataset->covers, &node);
bool nsec3, dns_dbnode_t **nodep DNS__DB_FLARG) {
isc_result_t result;
qpznode_t *node = NULL;
+ uint8_t denial = nsec3 ? DNS_DB_NSEC_NSEC3 : DNS_DB_NSEC_NORMAL;
dns_qpmulti_t *dbtree = nsec3 ? qpdb->nsec3 : qpdb->tree;
dns_qpread_t qpr = { 0 };
dns_qp_t *qp = NULL;
qp = (dns_qp_t *)&qpr;
}
- result = dns_qp_getname(qp, name, (void **)&node, NULL);
+ result = dns_qp_getname(qp, name, denial, (void **)&node, NULL);
if (result != ISC_R_SUCCESS) {
if (!create) {
dns_qpread_destroy(dbtree, &qpr);
}
node = new_qpznode(qpdb, name);
+ node->nsec = denial;
result = dns_qp_insert(qp, node, 0);
INSIST(result == ISC_R_SUCCESS);
qpznode_unref(node);
- if (nsec3) {
- node->nsec = DNS_DB_NSEC_NSEC3;
- } else {
- addwildcards(qpdb, qp, name);
+ if (!nsec3) {
+ addwildcards(qpdb, qp, name, denial);
if (dns_name_iswildcard(name)) {
- wildcardmagic(qpdb, qp, name);
+ wildcardmagic(qpdb, qp, name, denial);
}
}
}
}
static isc_result_t
-find_wildcard(qpz_search_t *search, qpznode_t **nodep,
- const dns_name_t *qname) {
+find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname,
+ uint8_t denial) {
dns_slabheader_t *header = NULL;
isc_result_t result = ISC_R_NOTFOUND;
break;
}
- result = dns_qp_lookup(&search->qpr, wname, NULL, &wit,
- NULL, (void **)&wnode, NULL);
+ result = dns_qp_lookup2(&search->qpr, wname, denial,
+ NULL, &wit, NULL,
+ (void **)&wnode, NULL);
if (result == ISC_R_SUCCESS) {
/*
* We have found the wildcard node. If it
* It is the first node sought in the NSEC tree.
*/
*firstp = false;
- result = dns_qp_lookup(&qpr, name, NULL, nit, NULL,
- NULL, NULL);
+ result = dns_qp_lookup2(&qpr, name, DNS_DB_NSEC_NSEC,
+ NULL, nit, NULL, NULL, NULL);
INSIST(result != ISC_R_NOTFOUND);
if (result == ISC_R_SUCCESS) {
/*
}
*nodep = NULL;
- result = dns_qp_lookup(&search->qpr, name, NULL, &search->iter,
- &search->chain, (void **)nodep, NULL);
+ result = dns_qp_lookup2(&search->qpr, name, DNS_DB_NSEC_NORMAL,
+ NULL, &search->iter, &search->chain,
+ (void **)nodep, NULL);
if (result == ISC_R_SUCCESS) {
break;
}
*nodep = (dns_dbnode_t *)node;
}
bindrdataset(search->qpdb, node, found,
-
rdataset DNS__DB_FLARG_PASS);
if (foundsig != NULL) {
bindrdataset(
search->qpdb, node, foundsig,
-
sigrdataset DNS__DB_FLARG_PASS);
}
} else if (found == NULL && foundsig == NULL) {
close_version = true;
}
+ uint8_t denial;
qpz_search_t search;
qpz_search_init(&search, (qpzonedb_t *)db, (qpz_version_t *)version,
options);
if ((options & DNS_DBFIND_FORCENSEC3) != 0) {
dns_qpmulti_query(qpdb->nsec3, &search.qpr);
nsec3 = true;
+ denial = DNS_DB_NSEC_NSEC3;
} else {
dns_qpmulti_query(qpdb->tree, &search.qpr);
+ denial = DNS_DB_NSEC_NORMAL;
}
/*
* Search down from the root of the tree.
*/
- result = dns_qp_lookup(&search.qpr, name, NULL, &search.iter,
- &search.chain, (void **)&node, NULL);
+ result = dns_qp_lookup2(&search.qpr, name, denial, NULL, &search.iter,
+ &search.chain, (void **)&node, NULL);
if (result != ISC_R_NOTFOUND) {
dns_name_copy(&node->name, foundname);
}
* we must see if there's a matching wildcard active
* in the current version.
*/
- result = find_wildcard(&search, &node, name);
+ result = find_wildcard(&search, &node, name, denial);
if (result == ISC_R_SUCCESS) {
dns_name_copy(name, foundname);
wild = true;
switch (qpdbiter->nsec3mode) {
case nsec3only:
qpdbiter->current = &qpdbiter->nsec3iter;
- result = dns_qp_lookup(qpdbiter->nsnap, name, NULL,
- qpdbiter->current, NULL,
- (void **)&qpdbiter->node, NULL);
+ result = dns_qp_lookup2(qpdbiter->nsnap, name,
+ DNS_DB_NSEC_NSEC3, NULL,
+ qpdbiter->current, NULL,
+ (void **)&qpdbiter->node, NULL);
break;
case nonsec3:
qpdbiter->current = &qpdbiter->mainiter;
qpdbiter->current, NULL,
(void **)&qpdbiter->node, NULL);
if (result == DNS_R_PARTIALMATCH) {
- tresult = dns_qp_lookup(qpdbiter->nsnap, name, NULL,
- &qpdbiter->nsec3iter, NULL,
- NULL, NULL);
+ tresult = dns_qp_lookup2(
+ qpdbiter->nsnap, name, DNS_DB_NSEC_NSEC3, NULL,
+ &qpdbiter->nsec3iter, NULL, NULL, NULL);
if (tresult == ISC_R_SUCCESS) {
qpdbiter->current = &qpdbiter->nsec3iter;
result = tresult;
/*
* Add to the auxiliary NSEC tree if we're adding an NSEC record.
*/
- if (node->nsec != DNS_DB_NSEC_HAS_NSEC &&
- rdataset->type == dns_rdatatype_nsec)
- {
+ if (!node->havensec && rdataset->type == dns_rdatatype_nsec) {
dns_qpmulti_write(qpdb->nsec, &nsec);
}
result = ISC_R_SUCCESS;
if (nsec != NULL) {
- node->nsec = DNS_DB_NSEC_HAS_NSEC;
+ node->havensec = true;
/*
* If it fails, there was already an NSEC node,
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
qpznode_t *data = pval;
- return dns_qpkey_fromname(key, &data->name);
+ return dns_qpkey_fromname(key, &data->name, data->nsec);
}
static void
dns_qp_t *qp = NULL;
dns_qpmulti_write(rpzs->table, &qp);
- result = dns_qp_getname(qp, trig_name, (void **)&data, NULL);
+ result = dns_qp_getname(qp, trig_name, 0, (void **)&data, NULL);
if (result != ISC_R_SUCCESS) {
INSIST(data == NULL);
data = new_nmdata(rpzs->mctx, trig_name, new_data);
trig_name = dns_fixedname_initname(&trig_namef);
name2data(rpz, rpz_type, src_name, trig_name, &del_data);
- result = dns_qp_getname(qp, trig_name, (void **)&data, NULL);
+ result = dns_qp_getname(qp, trig_name, 0, (void **)&data, NULL);
if (result != ISC_R_SUCCESS) {
return;
}
if (data->set.qname == 0 && data->set.ns == 0 &&
data->wild.qname == 0 && data->wild.ns == 0)
{
- result = dns_qp_deletename(qp, trig_name, NULL, NULL);
+ result = dns_qp_deletename(qp, trig_name, 0, NULL, NULL);
if (result != ISC_R_SUCCESS) {
/*
* bin/tests/system/rpz/tests.sh looks for
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
nmdata_t *data = pval;
- return dns_qpkey_fromname(key, &data->name);
+ return dns_qpkey_fromname(key, &data->name, 0);
}
static void
uint32_t ival ISC_ATTR_UNUSED) {
dns_zone_t *zone = pval;
dns_name_t *name = dns_zone_getorigin(zone);
- return dns_qpkey_fromname(key, name);
+ return dns_qpkey_fromname(key, name, 0);
}
static void
REQUIRE(VALID_ZT(zt));
dns_qpmulti_write(zt->multi, &qp);
- result = dns_qp_deletename(qp, dns_zone_getorigin(zone), NULL, NULL);
+ result = dns_qp_deletename(qp, dns_zone_getorigin(zone), 0, NULL, NULL);
dns_qp_compact(qp, DNS_QPGC_MAYBE);
dns_qpmulti_commit(zt->multi, &qp);
dns_qpmulti_query(zt->multi, &qpr);
if (exactopts == DNS_ZTFIND_EXACT) {
- result = dns_qp_getname(&qpr, name, &pval, NULL);
+ result = dns_qp_getname(&qpr, name, 0, &pval, NULL);
} else {
result = dns_qp_lookup(&qpr, name, NULL, NULL, &chain, &pval,
NULL);
item_makekey(dns_qpkey_t key, void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
assert(pval == &item[ival]);
- return dns_qpkey_fromname(key, &item[ival].fixed.name);
+ return dns_qpkey_fromname(key, &item[ival].fixed.name, 0);
}
static void
static isc_result_t
get_qp(void *qp, size_t count, void **pval) {
- return dns_qp_getname(qp, &item[count].fixed.name, pval, NULL);
+ return dns_qp_getname(qp, &item[count].fixed.name, 0, pval, NULL);
}
static void *
UNUSED(ctx);
dns_name_t name = DNS_NAME_INITEMPTY;
name_from_smallname(&name, pval, ival);
- return dns_qpkey_fromname(key, &name);
+ return dns_qpkey_fromname(key, &name, 0);
}
static void
UNUSED(ctx);
dns_name_t name = DNS_NAME_INITEMPTY;
name_from_smallname(&name, pval, ival);
- return dns_qpkey_fromname(key, &name);
+ return dns_qpkey_fromname(key, &name, 0);
}
static void
start = isc_time_monotonic();
for (i = 0; i < n; i++) {
name = dns_fixedname_name(&items[i]);
- dns_qp_getname(qp, name, NULL, NULL);
+ dns_qp_getname(qp, name, 0, NULL, NULL);
}
stop = isc_time_monotonic();
for (size_t i = 0; i < ITEM_COUNT; i++) {
do {
size_t len = isc_random_uniform(16) + 4;
- item[i].len = len;
- for (size_t off = 0; off < len; off++) {
+ item[i].len = len + 1;
+ item[i].key[0] = 0;
+ for (size_t off = 1; off < len; off++) {
item[i].key[off] = random_byte();
}
item[i].key[len] = SHIFT_NOBYTE;
ISC_RUN_TEST_IMPL(qpkey_name) {
struct {
const char *namestr;
+ uint8_t denial;
uint8_t key[512];
size_t len;
} testcases[] = {
{
.namestr = "",
- .key = { 0x02 },
- .len = 0,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x02 },
+ .len = 1,
},
{
.namestr = ".",
- .key = { 0x02, 0x02 },
- .len = 1,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x02, 0x02 },
+ .len = 2,
},
{
.namestr = "\\000",
- .key = { 0x03, 0x03, 0x02 },
- .len = 3,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x03, 0x03, 0x02 },
+ .len = 4,
},
{
.namestr = "\\000\\009",
- .key = { 0x03, 0x03, 0x03, 0x0c, 0x02 },
- .len = 5,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x03, 0x03, 0x03, 0x0c, 0x02 },
+ .len = 6,
},
{
.namestr = "com",
- .key = { 0x16, 0x22, 0x20, 0x02 },
- .len = 4,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x16, 0x22, 0x20, 0x02 },
+ .len = 5,
},
{
.namestr = "com.",
- .key = { 0x02, 0x16, 0x22, 0x20, 0x02 },
- .len = 5,
+ .denial = DNS_DB_NSEC_NSEC,
+ .key = { 0x02, 0x02, 0x16, 0x22, 0x20, 0x02 },
+ .len = 6,
+ },
+ {
+ .namestr = "com.",
+ .denial = DNS_DB_NSEC_NSEC3,
+ .key = { 0x03, 0x02, 0x16, 0x22, 0x20, 0x02 },
+ .len = 6,
+ },
+ {
+ .namestr = "com.",
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x02, 0x16, 0x22, 0x20, 0x02 },
+ .len = 6,
},
{
.namestr = "example.com.",
- .key = { 0x02, 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14,
- 0x20, 0x23, 0x1f, 0x18, 0x02 },
- .len = 13,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x02, 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b,
+ 0x14, 0x20, 0x23, 0x1f, 0x18, 0x02 },
+ .len = 14,
},
{
.namestr = "example.com",
- .key = { 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14, 0x20,
- 0x23, 0x1f, 0x18, 0x02 },
- .len = 12,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14,
+ 0x20, 0x23, 0x1f, 0x18, 0x02 },
+ .len = 13,
},
{
.namestr = "EXAMPLE.COM",
- .key = { 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14, 0x20,
- 0x23, 0x1f, 0x18, 0x02 },
- .len = 12,
+ .denial = DNS_DB_NSEC_NORMAL,
+ .key = { 0x00, 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14,
+ 0x20, 0x23, 0x1f, 0x18, 0x02 },
+ .len = 13,
},
};
dns_fixedname_t fn1, fn2;
dns_name_t *in = NULL, *out = NULL;
char namebuf[DNS_NAME_FORMATSIZE];
+ uint8_t denial;
in = dns_fixedname_initname(&fn1);
- if (testcases[i].len != 0) {
+ if (testcases[i].len > 1) {
dns_test_namefromstring(testcases[i].namestr, &fn1);
}
- len = dns_qpkey_fromname(key, in);
+ len = dns_qpkey_fromname(key, in, testcases[i].denial);
if (verbose) {
qp_test_printkey(key, len);
}
assert_int_equal(testcases[i].len, len);
assert_memory_equal(testcases[i].key, key, len);
- /* also check key correctness for empty name */
- if (len == 0) {
- assert_int_equal(testcases[i].key[0], ((char *)key)[0]);
- }
out = dns_fixedname_initname(&fn2);
- dns_qpkey_toname(key, len, out);
+ dns_qpkey_toname(key, len, out, &denial);
assert_true(dns_name_equal(in, out));
+ assert_int_equal(denial, testcases[i].denial);
/* check that 'out' is properly reset by dns_qpkey_toname */
- dns_qpkey_toname(key, len, out);
+ dns_qpkey_toname(key, len, out, NULL);
dns_name_format(out, namebuf, sizeof(namebuf));
}
}
&testcases[i].fixed);
testcases[i].name = dns_fixedname_name(&testcases[i].fixed);
testcases[i].len = dns_qpkey_fromname(testcases[i].key,
- testcases[i].name);
+ testcases[i].name, 0);
}
for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
return 0;
}
dns_test_namefromstring(pval, &fixed);
- return dns_qpkey_fromname(key, dns_fixedname_name(&fixed));
+ return dns_qpkey_fromname(key, dns_fixedname_name(&fixed), 0);
}
const dns_qpmethods_t string_methods = {
* what if entries in the trie are relative to the zone apex
* and there's no root node?
*/
- dns_qpkey_t rootkey = { SHIFT_NOBYTE };
+ dns_qpkey_t rootkey = { 0x00, SHIFT_NOBYTE };
result = dns_qp_deletekey(qp, rootkey, 1, NULL, NULL);
assert_int_equal(result, ISC_R_SUCCESS);
check_partialmatch(qp, (struct check_partialmatch[]){
{ NULL, 0, NULL },
});
- /* what if there's a root node with an empty key? */
- INSIST(insert[i][0] == '\0');
- insert_str(qp, insert[i++]);
- check_partialmatch(qp, (struct check_partialmatch[]){
- { "bar", DNS_R_PARTIALMATCH, "" },
- { "bar.", DNS_R_PARTIALMATCH, "" },
- { NULL, 0, NULL },
- });
-
dns_qp_destroy(&qp);
}
#include <isc/urcu.h>
#include <isc/util.h>
+#include <dns/db.h>
#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/qp.h>
const char *
qp_test_keytoascii(dns_qpkey_t key, size_t len) {
- for (size_t offset = 0; offset < len; offset++) {
+ for (size_t offset = 1; offset < len; offset++) {
key[offset] = qp_test_bittoascii(key[offset]);
}
key[len] = '\0';
qp_test_printkey(const dns_qpkey_t key, size_t keylen) {
dns_fixedname_t fn;
dns_name_t *n = dns_fixedname_initname(&fn);
+ uint8_t d;
char txt[DNS_NAME_FORMATSIZE];
- dns_qpkey_toname(key, keylen, n);
+ dns_qpkey_toname(key, keylen, n, &d);
dns_name_format(n, txt, sizeof(txt));
- printf("%s%s\n", txt, dns_name_isabsolute(n) ? "." : "");
+ printf("%s%s%s\n", txt,
+ d == DNS_DB_NSEC_NSEC3 ? "NSEC3:"
+ : (d == DNS_DB_NSEC_NSEC ? "NSEC" : ""),
+ dns_name_isabsolute(n) ? "." : "");
}
/**********************************************************************/