mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
modify dns_qp_findname_ancestor() to return found name
add a 'foundname' parameter to dns_qp_findname_ancestor(), and use it to set the found name in dns_nametree. this required adding a dns_qpkey_toname() function; that was done by moving qp_test_keytoname() from the test library to qp.c. added some more test cases and fixed bugs with the handling of relative and empty names.
This commit is contained in:
parent
06ac957c4f
commit
29cf7dceb7
@ -56,7 +56,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
|
|
||||||
/* verify round-trip conversion of first name */
|
/* verify round-trip conversion of first name */
|
||||||
size_t keylen = dns_qpkey_fromname(key, namein);
|
size_t keylen = dns_qpkey_fromname(key, namein);
|
||||||
qp_test_keytoname(key, keylen, nameout);
|
dns_qpkey_toname(key, keylen, nameout);
|
||||||
|
|
||||||
assert(dns_name_equal(namein, nameout));
|
assert(dns_name_equal(namein, nameout));
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name,
|
|||||||
REQUIRE(VALID_FWDTABLE(fwdtable));
|
REQUIRE(VALID_FWDTABLE(fwdtable));
|
||||||
|
|
||||||
dns_qpmulti_query(fwdtable->table, &qpr);
|
dns_qpmulti_query(fwdtable->table, &qpr);
|
||||||
result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
|
result = dns_qp_findname_ancestor(&qpr, name, 0, NULL, &pval, NULL);
|
||||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||||
dns_forwarders_t *fwdrs = pval;
|
dns_forwarders_t *fwdrs = pval;
|
||||||
*forwardersp = fwdrs;
|
*forwardersp = fwdrs;
|
||||||
|
@ -431,6 +431,17 @@ dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name);
|
|||||||
* \li the length of the key
|
* \li the length of the key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_qpkey_toname(const dns_qpkey_t key, size_t keylen, dns_name_t *name);
|
||||||
|
/*%<
|
||||||
|
* Convert a trie lookup key back into a DNS name.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li `name` is a pointer to a valid `dns_name_t`
|
||||||
|
* \li `name->buffer` is not NULL
|
||||||
|
* \li `name->offsets` is not NULL
|
||||||
|
*/
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_qp_getkey(dns_qpreadable_t qpr, const dns_qpkey_t search_key,
|
dns_qp_getkey(dns_qpreadable_t qpr, const dns_qpkey_t search_key,
|
||||||
size_t search_keylen, void **pval_r, uint32_t *ival_r);
|
size_t search_keylen, void **pval_r, uint32_t *ival_r);
|
||||||
@ -469,7 +480,8 @@ dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, void **pval_r,
|
|||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||||
dns_qpfind_t options, void **pval_r, uint32_t *ival_r);
|
dns_qpfind_t options, dns_name_t *foundname,
|
||||||
|
void **pval_r, uint32_t *ival_r);
|
||||||
/*%<
|
/*%<
|
||||||
* Find a leaf in a qp-trie that is an ancestor domain of, or equal to, the
|
* Find a leaf in a qp-trie that is an ancestor domain of, or equal to, the
|
||||||
* given DNS name.
|
* given DNS name.
|
||||||
@ -477,12 +489,16 @@ dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
|||||||
* If the DNS_QPFIND_NOEXACT option is set, find the closest ancestor
|
* If the DNS_QPFIND_NOEXACT option is set, find the closest ancestor
|
||||||
* domain that is not equal to the search name.
|
* domain that is not equal to the search name.
|
||||||
*
|
*
|
||||||
|
* If 'foundname' is not NULL, it is updated to contain the name found.
|
||||||
|
*
|
||||||
* The leaf values are assigned to whichever of `*pval_r` and `*ival_r`
|
* The leaf values are assigned to whichever of `*pval_r` and `*ival_r`
|
||||||
* are not null, unless the return value is ISC_R_NOTFOUND.
|
* are not null, unless the return value is ISC_R_NOTFOUND.
|
||||||
*
|
*
|
||||||
* Requires:
|
* Requires:
|
||||||
* \li `qpr` is a pointer to a readable qp-trie
|
* \li `qpr` is a pointer to a readable qp-trie
|
||||||
* \li `name` is a pointer to a valid `dns_name_t`
|
* \li `name` is a pointer to a valid `dns_name_t`
|
||||||
|
* \li `foundname` is a pointer to a valid `dns_name_t` with
|
||||||
|
* buffer and offset space available, or is NULL.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* \li ISC_R_SUCCESS if an exact match was found
|
* \li ISC_R_SUCCESS if an exact match was found
|
||||||
|
@ -518,7 +518,7 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
|
|||||||
REQUIRE(foundname != NULL);
|
REQUIRE(foundname != NULL);
|
||||||
|
|
||||||
dns_qpmulti_query(keytable->table, &qpr);
|
dns_qpmulti_query(keytable->table, &qpr);
|
||||||
result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
|
result = dns_qp_findname_ancestor(&qpr, name, 0, NULL, &pval, NULL);
|
||||||
keynode = pval;
|
keynode = pval;
|
||||||
|
|
||||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||||
@ -547,7 +547,7 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
|
|||||||
REQUIRE(wantdnssecp != NULL);
|
REQUIRE(wantdnssecp != NULL);
|
||||||
|
|
||||||
dns_qpmulti_query(keytable->table, &qpr);
|
dns_qpmulti_query(keytable->table, &qpr);
|
||||||
result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
|
result = dns_qp_findname_ancestor(&qpr, name, 0, NULL, &pval, NULL);
|
||||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||||
keynode = pval;
|
keynode = pval;
|
||||||
if (foundname != NULL) {
|
if (foundname != NULL) {
|
||||||
|
@ -289,12 +289,9 @@ dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
|
|||||||
REQUIRE(VALID_NAMETREE(nametree));
|
REQUIRE(VALID_NAMETREE(nametree));
|
||||||
|
|
||||||
dns_qpmulti_query(nametree->table, &qpr);
|
dns_qpmulti_query(nametree->table, &qpr);
|
||||||
result = dns_qp_findname_ancestor(&qpr, name, 0, (void **)&node, NULL);
|
result = dns_qp_findname_ancestor(&qpr, name, 0, found, (void **)&node,
|
||||||
|
NULL);
|
||||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||||
if (found != NULL) {
|
|
||||||
dns_name_copy(node->name, found);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nametree->type) {
|
switch (nametree->type) {
|
||||||
case DNS_NAMETREE_BOOL:
|
case DNS_NAMETREE_BOOL:
|
||||||
ret = node->set;
|
ret = node->set;
|
||||||
|
@ -413,7 +413,7 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
|
|||||||
|
|
||||||
RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
|
RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
|
||||||
dns_qpmulti_query(ntatable->table, &qpr);
|
dns_qpmulti_query(ntatable->table, &qpr);
|
||||||
result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
|
result = dns_qp_findname_ancestor(&qpr, name, 0, NULL, &pval, NULL);
|
||||||
nta = pval;
|
nta = pval;
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
99
lib/dns/qp.c
99
lib/dns/qp.c
@ -176,7 +176,7 @@ initialize_bits_for_byte(void) {
|
|||||||
qp_shift_t letter = byte - 'A';
|
qp_shift_t letter = byte - 'A';
|
||||||
qp_shift_t bit = after_esc + skip_punct + letter;
|
qp_shift_t bit = after_esc + skip_punct + letter;
|
||||||
dns_qp_bits_for_byte[byte] = bit;
|
dns_qp_bits_for_byte[byte] = bit;
|
||||||
/* to simplify reverse conversion in the tests */
|
/* to simplify reverse conversion */
|
||||||
bit_two++;
|
bit_two++;
|
||||||
} else {
|
} else {
|
||||||
/* non-hostname characters need to be escaped */
|
/* non-hostname characters need to be escaped */
|
||||||
@ -216,7 +216,11 @@ dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name) {
|
|||||||
dns_fixedname_t fixed;
|
dns_fixedname_t fixed;
|
||||||
|
|
||||||
REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
|
REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
|
||||||
REQUIRE(name->labels > 0);
|
|
||||||
|
if (name->labels == 0) {
|
||||||
|
key[0] = SHIFT_NOBYTE;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
if (name->offsets == NULL) {
|
if (name->offsets == NULL) {
|
||||||
dns_name_t *clone = dns_fixedname_initname(&fixed);
|
dns_name_t *clone = dns_fixedname_initname(&fixed);
|
||||||
@ -245,6 +249,85 @@ dns_qpkey_fromname(dns_qpkey_t key, const dns_name_t *name) {
|
|||||||
return (len);
|
return (len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_qpkey_toname(const dns_qpkey_t key, size_t keylen, dns_name_t *name) {
|
||||||
|
size_t locs[DNS_NAME_MAXLABELS];
|
||||||
|
size_t loc = 0, opos = 0;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
|
||||||
|
REQUIRE(name->buffer != NULL);
|
||||||
|
REQUIRE(name->offsets != NULL);
|
||||||
|
|
||||||
|
if (keylen == 0) {
|
||||||
|
dns_name_reset(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_buffer_clear(name->buffer);
|
||||||
|
|
||||||
|
/* Scan the key looking for label boundaries */
|
||||||
|
for (offset = 0; offset <= keylen; offset++) {
|
||||||
|
INSIST(key[offset] >= SHIFT_NOBYTE &&
|
||||||
|
key[offset] < SHIFT_OFFSET);
|
||||||
|
INSIST(loc < DNS_NAME_MAXLABELS);
|
||||||
|
if (qpkey_bit(key, keylen, offset) == SHIFT_NOBYTE) {
|
||||||
|
if (qpkey_bit(key, keylen, offset + 1) == SHIFT_NOBYTE)
|
||||||
|
{
|
||||||
|
locs[loc] = offset + 1;
|
||||||
|
goto scanned;
|
||||||
|
}
|
||||||
|
locs[loc++] = offset + 1;
|
||||||
|
} else if (offset == 0) {
|
||||||
|
/* This happens for a relative name */
|
||||||
|
locs[loc++] = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
scanned:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the key the labels are encoded in reverse order, so
|
||||||
|
* we step backward through the label boundaries, then forward
|
||||||
|
* through the labels, to create the DNS wire format data.
|
||||||
|
*/
|
||||||
|
name->labels = loc;
|
||||||
|
while (loc-- > 0) {
|
||||||
|
uint8_t len = 0, *lenp = NULL;
|
||||||
|
|
||||||
|
/* Add a length byte to the name data and set an offset */
|
||||||
|
lenp = isc_buffer_used(name->buffer);
|
||||||
|
isc_buffer_putuint8(name->buffer, 0);
|
||||||
|
name->offsets[opos++] = name->length++;
|
||||||
|
|
||||||
|
/* Convert from escaped byte ranges to ASCII */
|
||||||
|
for (offset = locs[loc]; offset < locs[loc + 1] - 1; offset++) {
|
||||||
|
uint8_t bit = qpkey_bit(key, keylen, offset);
|
||||||
|
uint8_t byte = dns_qp_byte_for_bit[bit];
|
||||||
|
if (qp_common_character(byte)) {
|
||||||
|
isc_buffer_putuint8(name->buffer, byte);
|
||||||
|
} else {
|
||||||
|
byte += key[++offset] - SHIFT_BITMAP;
|
||||||
|
isc_buffer_putuint8(name->buffer, byte);
|
||||||
|
}
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
name->length += len;
|
||||||
|
*lenp = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a root label for absolute names */
|
||||||
|
if (key[0] == SHIFT_NOBYTE) {
|
||||||
|
name->attributes.absolute = true;
|
||||||
|
isc_buffer_putuint8(name->buffer, 0);
|
||||||
|
name->offsets[opos++] = name->length++;
|
||||||
|
name->labels++;
|
||||||
|
}
|
||||||
|
|
||||||
|
name->ndata = isc_buffer_base(name->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sentinel value for equal keys
|
* Sentinel value for equal keys
|
||||||
*/
|
*/
|
||||||
@ -1811,8 +1894,8 @@ dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, void **pval_r,
|
|||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||||
dns_qpfind_t options, void **pval_r,
|
dns_qpfind_t options, dns_name_t *foundname,
|
||||||
uint32_t *ival_r) {
|
void **pval_r, uint32_t *ival_r) {
|
||||||
dns_qpreader_t *qp = dns_qpreader(qpr);
|
dns_qpreader_t *qp = dns_qpreader(qpr);
|
||||||
dns_qpkey_t search, found;
|
dns_qpkey_t search, found;
|
||||||
size_t searchlen, foundlen;
|
size_t searchlen, foundlen;
|
||||||
@ -1827,6 +1910,7 @@ dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
|||||||
} label[DNS_NAME_MAXLABELS];
|
} label[DNS_NAME_MAXLABELS];
|
||||||
|
|
||||||
REQUIRE(QP_VALID(qp));
|
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);
|
||||||
if ((options & DNS_QPFIND_NOEXACT) != 0) {
|
if ((options & DNS_QPFIND_NOEXACT) != 0) {
|
||||||
@ -1888,6 +1972,9 @@ dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
|||||||
if (offset == QPKEY_EQUAL || offset == foundlen) {
|
if (offset == QPKEY_EQUAL || offset == foundlen) {
|
||||||
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
|
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
|
||||||
SET_IF_NOT_NULL(ival_r, leaf_ival(n));
|
SET_IF_NOT_NULL(ival_r, leaf_ival(n));
|
||||||
|
if (foundname != NULL) {
|
||||||
|
dns_qpkey_toname(found, foundlen, foundname);
|
||||||
|
}
|
||||||
if (offset == QPKEY_EQUAL) {
|
if (offset == QPKEY_EQUAL) {
|
||||||
return (result);
|
return (result);
|
||||||
} else {
|
} else {
|
||||||
@ -1899,6 +1986,10 @@ dns_qp_findname_ancestor(dns_qpreadable_t qpr, const dns_name_t *name,
|
|||||||
n = ref_ptr(qp, label[labels].ref);
|
n = ref_ptr(qp, label[labels].ref);
|
||||||
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
|
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
|
||||||
SET_IF_NOT_NULL(ival_r, leaf_ival(n));
|
SET_IF_NOT_NULL(ival_r, leaf_ival(n));
|
||||||
|
if (foundname != NULL) {
|
||||||
|
foundlen = leaf_qpkey(qp, n, found);
|
||||||
|
dns_qpkey_toname(found, foundlen, foundname);
|
||||||
|
}
|
||||||
return (DNS_R_PARTIALMATCH);
|
return (DNS_R_PARTIALMATCH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,9 +181,10 @@ dns_zt_find(dns_zt_t *zt, const dns_name_t *name, dns_ztfind_t options,
|
|||||||
result = dns_qp_getname(&qpr, name, &pval, NULL);
|
result = dns_qp_getname(&qpr, name, &pval, NULL);
|
||||||
} else if (exactopts == DNS_ZTFIND_NOEXACT) {
|
} else if (exactopts == DNS_ZTFIND_NOEXACT) {
|
||||||
result = dns_qp_findname_ancestor(
|
result = dns_qp_findname_ancestor(
|
||||||
&qpr, name, DNS_QPFIND_NOEXACT, &pval, NULL);
|
&qpr, name, DNS_QPFIND_NOEXACT, NULL, &pval, NULL);
|
||||||
} else {
|
} else {
|
||||||
result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
|
result = dns_qp_findname_ancestor(&qpr, name, 0, NULL, &pval,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
dns_qpread_destroy(zt->multi, &qpr);
|
dns_qpread_destroy(zt->multi, &qpr);
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ main(int argc, char **argv) {
|
|||||||
start = isc_time_monotonic();
|
start = isc_time_monotonic();
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
name = dns_fixedname_name(&items[i]);
|
name = dns_fixedname_name(&items[i]);
|
||||||
dns_qp_findname_ancestor(qp, name, 0, NULL, NULL);
|
dns_qp_findname_ancestor(qp, name, 0, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
stop = isc_time_monotonic();
|
stop = isc_time_monotonic();
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ main(int argc, char **argv) {
|
|||||||
++search->ndata[1];
|
++search->ndata[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
dns_qp_findname_ancestor(qp, search, 0, NULL, NULL);
|
dns_qp_findname_ancestor(qp, search, 0, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
stop = isc_time_monotonic();
|
stop = isc_time_monotonic();
|
||||||
|
|
||||||
|
@ -44,6 +44,11 @@ ISC_RUN_TEST_IMPL(qpkey_name) {
|
|||||||
uint8_t key[512];
|
uint8_t key[512];
|
||||||
size_t len;
|
size_t len;
|
||||||
} testcases[] = {
|
} testcases[] = {
|
||||||
|
{
|
||||||
|
.namestr = "",
|
||||||
|
.key = { 0x02 },
|
||||||
|
.len = 0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.namestr = ".",
|
.namestr = ".",
|
||||||
.key = { 0x02, 0x02 },
|
.key = { 0x02, 0x02 },
|
||||||
@ -54,6 +59,16 @@ ISC_RUN_TEST_IMPL(qpkey_name) {
|
|||||||
.key = { 0x03, 0x03, 0x02, 0x02 },
|
.key = { 0x03, 0x03, 0x02, 0x02 },
|
||||||
.len = 3,
|
.len = 3,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.namestr = "com",
|
||||||
|
.key = { 0x16, 0x22, 0x20, 0x02 },
|
||||||
|
.len = 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.namestr = "com.",
|
||||||
|
.key = { 0x02, 0x16, 0x22, 0x20, 0x02 },
|
||||||
|
.len = 5,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.namestr = "example.com.",
|
.namestr = "example.com.",
|
||||||
.key = { 0x02, 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14,
|
.key = { 0x02, 0x16, 0x22, 0x20, 0x02, 0x18, 0x2b, 0x14,
|
||||||
@ -80,15 +95,21 @@ ISC_RUN_TEST_IMPL(qpkey_name) {
|
|||||||
dns_fixedname_t fn1, fn2;
|
dns_fixedname_t fn1, fn2;
|
||||||
dns_name_t *in = NULL, *out = NULL;
|
dns_name_t *in = NULL, *out = NULL;
|
||||||
|
|
||||||
|
in = dns_fixedname_initname(&fn1);
|
||||||
|
if (testcases[i].len != 0) {
|
||||||
dns_test_namefromstring(testcases[i].namestr, &fn1);
|
dns_test_namefromstring(testcases[i].namestr, &fn1);
|
||||||
in = dns_fixedname_name(&fn1);
|
}
|
||||||
len = dns_qpkey_fromname(key, in);
|
len = dns_qpkey_fromname(key, in);
|
||||||
|
|
||||||
assert_int_equal(testcases[i].len, len);
|
assert_int_equal(testcases[i].len, len);
|
||||||
assert_memory_equal(testcases[i].key, key, 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);
|
out = dns_fixedname_initname(&fn2);
|
||||||
qp_test_keytoname(key, len, out);
|
dns_qpkey_toname(key, len, out);
|
||||||
assert_true(dns_name_equal(in, out));
|
assert_true(dns_name_equal(in, out));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,19 +279,47 @@ static void
|
|||||||
check_partialmatch(dns_qp_t *qp, struct check_partialmatch check[]) {
|
check_partialmatch(dns_qp_t *qp, struct check_partialmatch check[]) {
|
||||||
for (int i = 0; check[i].query != NULL; i++) {
|
for (int i = 0; check[i].query != NULL; i++) {
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
dns_fixedname_t fixed;
|
dns_fixedname_t fn1, fn2;
|
||||||
dns_name_t *name = dns_fixedname_name(&fixed);
|
dns_name_t *name = dns_fixedname_initname(&fn1);
|
||||||
|
dns_name_t *foundname = dns_fixedname_initname(&fn2);
|
||||||
void *pval = NULL;
|
void *pval = NULL;
|
||||||
|
|
||||||
|
dns_test_namefromstring(check[i].query, &fn1);
|
||||||
|
result = dns_qp_findname_ancestor(qp, name, check[i].options,
|
||||||
|
foundname, &pval, NULL);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
fprintf(stderr, "%s %u %s %s\n", check[i].query,
|
fprintf(stderr, "%s (flags %u) %s (expected %s) "
|
||||||
check[i].options, isc_result_totext(check[i].result),
|
"value \"%s\" (expected \"%s\")\n",
|
||||||
|
check[i].query, check[i].options,
|
||||||
|
isc_result_totext(result),
|
||||||
|
isc_result_totext(check[i].result), (char *)pval,
|
||||||
check[i].found);
|
check[i].found);
|
||||||
#endif
|
#endif
|
||||||
dns_test_namefromstring(check[i].query, &fixed);
|
|
||||||
result = dns_qp_findname_ancestor(qp, name, check[i].options,
|
|
||||||
&pval, NULL);
|
|
||||||
assert_int_equal(result, check[i].result);
|
assert_int_equal(result, check[i].result);
|
||||||
|
if (result == ISC_R_SUCCESS) {
|
||||||
|
assert_true(dns_name_equal(name, foundname));
|
||||||
|
} else if (result == DNS_R_PARTIALMATCH) {
|
||||||
|
/*
|
||||||
|
* there are cases where we may have passed a
|
||||||
|
* query name that was relative to the zone apex,
|
||||||
|
* and gotten back an absolute name from the
|
||||||
|
* partial match. it's also possible for an
|
||||||
|
* absolute query to get a partial match on a
|
||||||
|
* node that had an empty name. in these cases,
|
||||||
|
* sanity checking the relations between name
|
||||||
|
* and foundname can trigger an assertion, so
|
||||||
|
* let's just skip them.
|
||||||
|
*/
|
||||||
|
if (dns_name_isabsolute(name) ==
|
||||||
|
dns_name_isabsolute(foundname))
|
||||||
|
{
|
||||||
|
assert_false(dns_name_equal(name, foundname));
|
||||||
|
assert_true(
|
||||||
|
dns_name_issubdomain(name, foundname));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (check[i].found == NULL) {
|
if (check[i].found == NULL) {
|
||||||
assert_null(pval);
|
assert_null(pval);
|
||||||
} else {
|
} else {
|
||||||
@ -291,6 +340,7 @@ insert_str(dns_qp_t *qp, const char *str) {
|
|||||||
ISC_RUN_TEST_IMPL(partialmatch) {
|
ISC_RUN_TEST_IMPL(partialmatch) {
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
dns_qp_t *qp = NULL;
|
dns_qp_t *qp = NULL;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
dns_qp_create(mctx, &string_methods, NULL, &qp);
|
dns_qp_create(mctx, &string_methods, NULL, &qp);
|
||||||
|
|
||||||
@ -302,7 +352,10 @@ ISC_RUN_TEST_IMPL(partialmatch) {
|
|||||||
"fooo.bar.", "web.foo.bar.", ".", "",
|
"fooo.bar.", "web.foo.bar.", ".", "",
|
||||||
};
|
};
|
||||||
|
|
||||||
int i = 0;
|
/*
|
||||||
|
* omit the root node for now, otherwise we'll get "partial match"
|
||||||
|
* results when we want "not found".
|
||||||
|
*/
|
||||||
while (insert[i][0] != '.') {
|
while (insert[i][0] != '.') {
|
||||||
insert_str(qp, insert[i++]);
|
insert_str(qp, insert[i++]);
|
||||||
}
|
}
|
||||||
@ -340,19 +393,39 @@ ISC_RUN_TEST_IMPL(partialmatch) {
|
|||||||
{ "bar.", 0, DNS_R_PARTIALMATCH, "." },
|
{ "bar.", 0, DNS_R_PARTIALMATCH, "." },
|
||||||
{ "foo.bar.", 0, ISC_R_SUCCESS, "foo.bar." },
|
{ "foo.bar.", 0, ISC_R_SUCCESS, "foo.bar." },
|
||||||
{ "foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "." },
|
{ "foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "." },
|
||||||
|
{ "bar", 0, ISC_R_NOTFOUND, NULL },
|
||||||
|
{ "bar", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "." },
|
||||||
{ NULL, 0, 0, NULL },
|
{ NULL, 0, 0, NULL },
|
||||||
};
|
};
|
||||||
check_partialmatch(qp, check2);
|
check_partialmatch(qp, check2);
|
||||||
|
|
||||||
/* what if entries in the trie are relative to the zone apex? */
|
/*
|
||||||
|
* 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 = { SHIFT_NOBYTE };
|
||||||
result = dns_qp_deletekey(qp, rootkey, 1, NULL, NULL);
|
result = dns_qp_deletekey(qp, rootkey, 1, NULL, NULL);
|
||||||
assert_int_equal(result, ISC_R_SUCCESS);
|
assert_int_equal(result, ISC_R_SUCCESS);
|
||||||
|
check_partialmatch(
|
||||||
|
qp,
|
||||||
|
(struct check_partialmatch[]){
|
||||||
|
{ "bar", 0, ISC_R_NOTFOUND, NULL },
|
||||||
|
{ "bar", DNS_QPFIND_NOEXACT, ISC_R_NOTFOUND, NULL },
|
||||||
|
{ "bar.", 0, ISC_R_NOTFOUND, NULL },
|
||||||
|
{ "bar.", DNS_QPFIND_NOEXACT, ISC_R_NOTFOUND, NULL },
|
||||||
|
{ NULL, 0, 0, NULL },
|
||||||
|
});
|
||||||
|
|
||||||
|
/* what if there's a root node with an empty key? */
|
||||||
INSIST(insert[i][0] == '\0');
|
INSIST(insert[i][0] == '\0');
|
||||||
insert_str(qp, insert[i++]);
|
insert_str(qp, insert[i++]);
|
||||||
check_partialmatch(qp, (struct check_partialmatch[]){
|
check_partialmatch(
|
||||||
|
qp,
|
||||||
|
(struct check_partialmatch[]){
|
||||||
{ "bar", 0, DNS_R_PARTIALMATCH, "" },
|
{ "bar", 0, DNS_R_PARTIALMATCH, "" },
|
||||||
|
{ "bar", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "" },
|
||||||
{ "bar.", 0, DNS_R_PARTIALMATCH, "" },
|
{ "bar.", 0, DNS_R_PARTIALMATCH, "" },
|
||||||
|
{ "bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "" },
|
||||||
{ NULL, 0, 0, NULL },
|
{ NULL, 0, 0, NULL },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,13 +29,6 @@ qp_test_bittoascii(uint8_t bit);
|
|||||||
const char *
|
const char *
|
||||||
qp_test_keytoascii(dns_qpkey_t key, size_t len);
|
qp_test_keytoascii(dns_qpkey_t key, size_t len);
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert a trie lookup key back into a DNS name. Unlike the previous
|
|
||||||
* functions, this is a complete inverse of dns_qpkey_fromname().
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
qp_test_keytoname(const dns_qpkey_t key, size_t len, dns_name_t *name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The maximum height of the trie
|
* The maximum height of the trie
|
||||||
*/
|
*/
|
||||||
|
@ -61,80 +61,6 @@ qp_test_keytoascii(dns_qpkey_t key, size_t len) {
|
|||||||
return ((const char *)key);
|
return ((const char *)key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
qp_test_keytoname(const dns_qpkey_t key, size_t keylen, dns_name_t *name) {
|
|
||||||
size_t locs[DNS_NAME_MAXLABELS];
|
|
||||||
size_t loc = 0, opos = 0;
|
|
||||||
size_t offset;
|
|
||||||
|
|
||||||
REQUIRE(ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
|
|
||||||
REQUIRE(name->buffer != NULL);
|
|
||||||
REQUIRE(name->offsets != NULL);
|
|
||||||
|
|
||||||
isc_buffer_clear(name->buffer);
|
|
||||||
|
|
||||||
/* Scan the key looking for label boundaries */
|
|
||||||
for (offset = 0; offset <= keylen; offset++) {
|
|
||||||
INSIST(key[offset] >= SHIFT_NOBYTE &&
|
|
||||||
key[offset] < SHIFT_OFFSET);
|
|
||||||
INSIST(loc < DNS_NAME_MAXLABELS);
|
|
||||||
if (qpkey_bit(key, keylen, offset) == SHIFT_NOBYTE) {
|
|
||||||
if (qpkey_bit(key, keylen, offset + 1) == SHIFT_NOBYTE)
|
|
||||||
{
|
|
||||||
locs[loc] = offset + 1;
|
|
||||||
goto scanned;
|
|
||||||
}
|
|
||||||
locs[loc++] = offset + 1;
|
|
||||||
} else if (offset == 0) {
|
|
||||||
/* This happens for a relative name */
|
|
||||||
locs[loc++] = offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
scanned:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In the key the labels are encoded in reverse order, so
|
|
||||||
* we step backward through the label boundaries, then forward
|
|
||||||
* through the labels, to create the DNS wire format data.
|
|
||||||
*/
|
|
||||||
name->labels = loc;
|
|
||||||
while (loc-- > 0) {
|
|
||||||
uint8_t len = 0, *lenp = NULL;
|
|
||||||
|
|
||||||
/* Add a length byte to the name data and set an offset */
|
|
||||||
lenp = isc_buffer_used(name->buffer);
|
|
||||||
isc_buffer_putuint8(name->buffer, 0);
|
|
||||||
name->offsets[opos++] = name->length++;
|
|
||||||
|
|
||||||
/* Convert from escaped byte ranges to ASCII */
|
|
||||||
for (offset = locs[loc]; offset < locs[loc + 1] - 1; offset++) {
|
|
||||||
uint8_t bit = qpkey_bit(key, keylen, offset);
|
|
||||||
uint8_t byte = dns_qp_byte_for_bit[bit];
|
|
||||||
if (qp_common_character(byte)) {
|
|
||||||
isc_buffer_putuint8(name->buffer, byte);
|
|
||||||
} else {
|
|
||||||
byte += key[++offset] - SHIFT_BITMAP;
|
|
||||||
isc_buffer_putuint8(name->buffer, byte);
|
|
||||||
}
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
name->length += len;
|
|
||||||
*lenp = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a root label for absolute names */
|
|
||||||
if (key[0] == SHIFT_NOBYTE) {
|
|
||||||
name->attributes.absolute = true;
|
|
||||||
isc_buffer_putuint8(name->buffer, 0);
|
|
||||||
name->length++;
|
|
||||||
name->labels++;
|
|
||||||
}
|
|
||||||
|
|
||||||
name->ndata = isc_buffer_base(name->buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
*
|
*
|
||||||
* trie properties
|
* trie properties
|
||||||
|
Loading…
x
Reference in New Issue
Block a user