mirror of
https://github.com/isc-projects/bind9.git
synced 2026-03-09 17:50:52 -04:00
The string literal initialalising compressed was too big for the array as it has an unwanted NUL terminator. This is allowed for in C for historical reasons but produces a warning with some compilers. Adjust the declaration to include the NUL and adjust the users to pass in an adjusted size which excludes the NUL rather than sizeof(compressed).
1034 lines
28 KiB
C
1034 lines
28 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <sched.h> /* IWYU pragma: keep */
|
|
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define UNIT_TESTING
|
|
#include <cmocka.h>
|
|
|
|
#include <isc/buffer.h>
|
|
#include <isc/commandline.h>
|
|
#include <isc/lib.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/os.h>
|
|
#include <isc/thread.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/compress.h>
|
|
#include <dns/fixedname.h>
|
|
#include <dns/lib.h>
|
|
#include <dns/name.h>
|
|
|
|
#include <tests/dns.h>
|
|
|
|
/* Set to true (or use -v option) for verbose output */
|
|
static bool verbose = false;
|
|
|
|
/* dns_name_fullcompare test */
|
|
ISC_RUN_TEST_IMPL(fullcompare) {
|
|
dns_fixedname_t fixed1;
|
|
dns_fixedname_t fixed2;
|
|
dns_name_t *name1;
|
|
dns_name_t *name2;
|
|
dns_namereln_t relation;
|
|
int i;
|
|
isc_result_t result;
|
|
struct {
|
|
const char *name1;
|
|
const char *name2;
|
|
dns_namereln_t relation;
|
|
int order;
|
|
unsigned int nlabels;
|
|
} data[] = {
|
|
/* relative */
|
|
{ "", "", dns_namereln_equal, 0, 0 },
|
|
{ "foo", "", dns_namereln_subdomain, 1, 0 },
|
|
{ "", "foo", dns_namereln_contains, -1, 0 },
|
|
{ "foo", "bar", dns_namereln_none, 1, 0 },
|
|
{ "bar", "foo", dns_namereln_none, -1, 0 },
|
|
{ "bar.foo", "foo", dns_namereln_subdomain, 1, 1 },
|
|
{ "foo", "bar.foo", dns_namereln_contains, -1, 1 },
|
|
{ "baz.bar.foo", "bar.foo", dns_namereln_subdomain, 1, 2 },
|
|
{ "bar.foo", "baz.bar.foo", dns_namereln_contains, -1, 2 },
|
|
{ "foo.example", "bar.example", dns_namereln_commonancestor, 1,
|
|
1 },
|
|
|
|
/* absolute */
|
|
{ ".", ".", dns_namereln_equal, 0, 1 },
|
|
{ "foo.", "bar.", dns_namereln_commonancestor, 1, 1 },
|
|
{ "bar.", "foo.", dns_namereln_commonancestor, -1, 1 },
|
|
{ "foo.example.", "bar.example.", dns_namereln_commonancestor,
|
|
1, 2 },
|
|
{ "bar.foo.", "foo.", dns_namereln_subdomain, 1, 2 },
|
|
{ "foo.", "bar.foo.", dns_namereln_contains, -1, 2 },
|
|
{ "baz.bar.foo.", "bar.foo.", dns_namereln_subdomain, 1, 3 },
|
|
{ "bar.foo.", "baz.bar.foo.", dns_namereln_contains, -1, 3 },
|
|
{ NULL, NULL, dns_namereln_none, 0, 0 }
|
|
};
|
|
|
|
UNUSED(state);
|
|
|
|
name1 = dns_fixedname_initname(&fixed1);
|
|
name2 = dns_fixedname_initname(&fixed2);
|
|
for (i = 0; data[i].name1 != NULL; i++) {
|
|
int order = 3000;
|
|
unsigned int nlabels = 3000;
|
|
|
|
if (data[i].name1[0] == 0) {
|
|
dns_fixedname_init(&fixed1);
|
|
} else {
|
|
result = dns_name_fromstring(name1, data[i].name1, NULL,
|
|
0, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
}
|
|
if (data[i].name2[0] == 0) {
|
|
dns_fixedname_init(&fixed2);
|
|
} else {
|
|
result = dns_name_fromstring(name2, data[i].name2, NULL,
|
|
0, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
}
|
|
relation = dns_name_fullcompare(name1, name1, &order, &nlabels);
|
|
assert_int_equal(relation, dns_namereln_equal);
|
|
assert_int_equal(order, 0);
|
|
|
|
uint8_t labels = dns_name_countlabels(name1);
|
|
assert_int_equal(nlabels, labels);
|
|
|
|
/* Some random initializer */
|
|
order = 3001;
|
|
nlabels = 3001;
|
|
|
|
relation = dns_name_fullcompare(name1, name2, &order, &nlabels);
|
|
assert_int_equal(relation, data[i].relation);
|
|
assert_int_equal(order, data[i].order);
|
|
assert_int_equal(nlabels, data[i].nlabels);
|
|
}
|
|
}
|
|
|
|
static void
|
|
compress_test(const dns_name_t *name1, const dns_name_t *name2,
|
|
const dns_name_t *name3, unsigned char *compressed,
|
|
unsigned int compressed_length, unsigned char *expanded,
|
|
unsigned int expanded_length, dns_compress_t *cctx,
|
|
dns_decompress_t dctx, bool rdata) {
|
|
isc_buffer_t source;
|
|
isc_buffer_t target;
|
|
dns_name_t name;
|
|
unsigned char buf1[1024];
|
|
unsigned char buf2[1024];
|
|
|
|
isc_buffer_init(&source, buf1, sizeof(buf1));
|
|
isc_buffer_init(&target, buf2, sizeof(buf2));
|
|
|
|
/*
|
|
* compression offsets are not allowed to be zero so our
|
|
* names need to start after a little fake header
|
|
*/
|
|
isc_buffer_putuint16(&source, 0xEAD);
|
|
isc_buffer_putuint16(&target, 0xEAD);
|
|
|
|
if (rdata) {
|
|
/* RDATA compression */
|
|
assert_int_equal(dns_name_towire(name1, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
assert_int_equal(dns_name_towire(name2, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
assert_int_equal(dns_name_towire(name2, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
assert_int_equal(dns_name_towire(name3, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
} else {
|
|
/* Owner name compression */
|
|
if (cctx != NULL) {
|
|
dns_compress_setmultiuse(cctx, true);
|
|
}
|
|
assert_int_equal(dns_name_towire(name1, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
|
|
if (cctx != NULL) {
|
|
dns_compress_setmultiuse(cctx, true);
|
|
}
|
|
assert_int_equal(dns_name_towire(name2, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
assert_int_equal(dns_name_towire(name2, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
|
|
if (cctx != NULL) {
|
|
dns_compress_setmultiuse(cctx, true);
|
|
}
|
|
assert_int_equal(dns_name_towire(name3, cctx, &source),
|
|
ISC_R_SUCCESS);
|
|
}
|
|
assert_int_equal(source.used, compressed_length);
|
|
assert_true(memcmp(source.base, compressed, source.used) == 0);
|
|
|
|
isc_buffer_setactive(&source, source.used);
|
|
|
|
dns_name_init(&name);
|
|
RUNTIME_CHECK(isc_buffer_getuint16(&source) == 0xEAD);
|
|
RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
|
|
ISC_R_SUCCESS);
|
|
RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
|
|
ISC_R_SUCCESS);
|
|
RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
|
|
ISC_R_SUCCESS);
|
|
RUNTIME_CHECK(dns_name_fromwire(&name, &source, dctx, &target) ==
|
|
ISC_R_SUCCESS);
|
|
|
|
assert_int_equal(target.used, expanded_length);
|
|
assert_true(memcmp(target.base, expanded, target.used) == 0);
|
|
}
|
|
|
|
/* name compression test */
|
|
ISC_RUN_TEST_IMPL(compression) {
|
|
bool permitted;
|
|
dns_compress_t cctx;
|
|
dns_decompress_t dctx;
|
|
dns_name_t name1;
|
|
dns_name_t name2;
|
|
dns_name_t name3;
|
|
dns_name_t name4;
|
|
isc_region_t r;
|
|
unsigned char plain1[] = "\003yyy\003foo";
|
|
unsigned char plain2[] = "\003bar\003yyy\003foo";
|
|
unsigned char plain3[] = "\003xxx\003bar\003foo";
|
|
unsigned char plain4[] = "\003xxx\003bar\003zzz";
|
|
|
|
unsigned char plain[] = "\x0E\xAD"
|
|
"\003yyy\003foo\0"
|
|
"\003bar\003yyy\003foo\0"
|
|
"\003bar\003yyy\003foo\0"
|
|
"\003xxx\003bar\003foo";
|
|
|
|
unsigned char compressed[] = "\x0E\xAD"
|
|
"\003yyy\003foo\0"
|
|
"\003bar\xc0\x02"
|
|
"\xc0\x0B"
|
|
"\003xxx\003bar\xc0\x06";
|
|
const size_t compressed_len = sizeof(compressed) - 1;
|
|
|
|
/*
|
|
* Only the second owner name is compressed.
|
|
*/
|
|
unsigned char disabled_owner[] = "\x0E\xAD"
|
|
"\003yyy\003foo\0"
|
|
"\003bar\003yyy\003foo\0"
|
|
"\xc0\x0B"
|
|
"\003xxx\003bar\003foo";
|
|
|
|
unsigned char root_plain[] = "\x0E\xAD"
|
|
"\003yyy\003foo\0"
|
|
"\0\0"
|
|
"\003xxx\003bar\003zzz";
|
|
|
|
UNUSED(state);
|
|
|
|
dns_name_init(&name1);
|
|
r.base = plain1;
|
|
r.length = sizeof(plain1);
|
|
dns_name_fromregion(&name1, &r);
|
|
|
|
dns_name_init(&name2);
|
|
r.base = plain2;
|
|
r.length = sizeof(plain2);
|
|
dns_name_fromregion(&name2, &r);
|
|
|
|
dns_name_init(&name3);
|
|
r.base = plain3;
|
|
r.length = sizeof(plain3);
|
|
dns_name_fromregion(&name3, &r);
|
|
|
|
dns_name_init(&name4);
|
|
r.base = plain4;
|
|
r.length = sizeof(plain3);
|
|
dns_name_fromregion(&name4, &r);
|
|
|
|
/* Test 0: no compression context */
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), NULL, DNS_DECOMPRESS_NEVER, true);
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), NULL, DNS_DECOMPRESS_NEVER, false);
|
|
|
|
/* Test 1: off, rdata */
|
|
permitted = false;
|
|
dns_compress_init(&cctx, mctx, 0);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), &cctx, dctx, true);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test2: on, rdata */
|
|
permitted = true;
|
|
dns_compress_init(&cctx, mctx, 0);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, compressed, compressed_len, plain,
|
|
sizeof(plain), &cctx, dctx, true);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test3: off, disabled, rdata */
|
|
permitted = false;
|
|
dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), &cctx, dctx, true);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test4: on, disabled, rdata */
|
|
permitted = true;
|
|
dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), &cctx, dctx, true);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test5: on, rdata */
|
|
permitted = true;
|
|
dns_compress_init(&cctx, mctx, 0);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, dns_rootname, &name4, root_plain,
|
|
sizeof(root_plain), root_plain, sizeof(root_plain), &cctx,
|
|
dctx, true);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test 6: off, owner */
|
|
permitted = false;
|
|
dns_compress_init(&cctx, mctx, 0);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), &cctx, dctx, false);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test7: on, owner */
|
|
permitted = true;
|
|
dns_compress_init(&cctx, mctx, 0);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, compressed, compressed_len, plain,
|
|
sizeof(plain), &cctx, dctx, false);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test8: off, disabled, owner */
|
|
permitted = false;
|
|
dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, plain, sizeof(plain), plain,
|
|
sizeof(plain), &cctx, dctx, false);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test9: on, disabled, owner */
|
|
permitted = true;
|
|
dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, &name2, &name3, disabled_owner,
|
|
sizeof(disabled_owner), plain, sizeof(plain), &cctx, dctx,
|
|
false);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
/* Test10: on, owner */
|
|
permitted = true;
|
|
dns_compress_init(&cctx, mctx, 0);
|
|
dns_compress_setpermitted(&cctx, permitted);
|
|
dctx = dns_decompress_setpermitted(DNS_DECOMPRESS_DEFAULT, permitted);
|
|
|
|
compress_test(&name1, dns_rootname, &name4, root_plain,
|
|
sizeof(root_plain), root_plain, sizeof(root_plain), &cctx,
|
|
dctx, false);
|
|
|
|
dns_compress_rollback(&cctx, 0);
|
|
dns_compress_invalidate(&cctx);
|
|
}
|
|
|
|
#define NAME_LO 25
|
|
#define NAME_HI 250000
|
|
|
|
/*
|
|
* test compression context hash set collisions and rollbacks
|
|
*/
|
|
ISC_RUN_TEST_IMPL(collision) {
|
|
isc_result_t result;
|
|
isc_region_t r;
|
|
dns_compress_t cctx;
|
|
isc_buffer_t message;
|
|
uint8_t msgbuf[65536];
|
|
dns_name_t name;
|
|
char namebuf[256];
|
|
|
|
dns_compress_init(&cctx, mctx, DNS_COMPRESS_LARGE);
|
|
isc_buffer_init(&message, msgbuf, sizeof(msgbuf));
|
|
dns_name_init(&name);
|
|
|
|
/*
|
|
* compression offsets are not allowed to be zero so our
|
|
* names need to start after a little fake header
|
|
*/
|
|
isc_buffer_putuint16(&message, 0xEAD);
|
|
|
|
static const char zone[] = "test";
|
|
const int zonelen = sizeof(zone) - 1;
|
|
unsigned int zone_coff = 0;
|
|
|
|
for (int i = NAME_LO; i < NAME_HI; i++) {
|
|
unsigned int prefix_len, suffix_coff;
|
|
unsigned int coff = isc_buffer_usedlength(&message);
|
|
|
|
int len = snprintf(namebuf, sizeof(namebuf), ".%d%c%s", i,
|
|
zonelen, zone);
|
|
namebuf[0] = len - zonelen - 2;
|
|
r = (isc_region_t){ .base = (uint8_t *)namebuf,
|
|
.length = len + 1 };
|
|
dns_name_fromregion(&name, &r);
|
|
|
|
/* the name we are about to add must partially match */
|
|
prefix_len = name.length;
|
|
suffix_coff = 0;
|
|
dns_compress_name(&cctx, &message, &name, &prefix_len,
|
|
&suffix_coff);
|
|
if (i == NAME_LO) {
|
|
assert_int_equal(prefix_len, name.length);
|
|
assert_int_equal(suffix_coff, 0);
|
|
zone_coff = 2 + len - zonelen - 1;
|
|
} else {
|
|
assert_int_equal(prefix_len, len - zonelen - 1);
|
|
assert_int_equal(suffix_coff, zone_coff);
|
|
}
|
|
dns_compress_rollback(&cctx, coff);
|
|
|
|
dns_compress_setmultiuse(&cctx, true);
|
|
result = dns_name_towire(&name, &cctx, &message);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/* we must be able to find the name we just added */
|
|
prefix_len = name.length;
|
|
suffix_coff = 0;
|
|
dns_compress_name(&cctx, &message, &name, &prefix_len,
|
|
&suffix_coff);
|
|
assert_int_equal(prefix_len, 0);
|
|
assert_int_equal(suffix_coff, coff);
|
|
|
|
/* don't let the hash set get too full */
|
|
if (cctx.count > cctx.mask * 3 / 5) {
|
|
dns_compress_rollback(&cctx, zone_coff + zonelen + 2);
|
|
isc_buffer_clear(&message);
|
|
isc_buffer_add(&message, zone_coff + zonelen + 2);
|
|
}
|
|
}
|
|
|
|
dns_compress_invalidate(&cctx);
|
|
}
|
|
|
|
ISC_RUN_TEST_IMPL(fromregion) {
|
|
dns_name_t name;
|
|
isc_buffer_t b;
|
|
isc_region_t r;
|
|
/*
|
|
* target and source need to be bigger than DNS_NAME_MAXWIRE to
|
|
* exercise 'len > DNS_NAME_MAXWIRE' test in dns_name_fromwire
|
|
*/
|
|
unsigned char target[DNS_NAME_MAXWIRE + 10];
|
|
unsigned char source[DNS_NAME_MAXWIRE + 10] = { '\007', 'e', 'x', 'a',
|
|
'm', 'p', 'l', 'e' };
|
|
/*
|
|
* Extract the fully qualified name at the beginning of 'source'
|
|
* into 'name' where 'name.ndata' points to the buffer 'target'.
|
|
*/
|
|
isc_buffer_init(&b, target, sizeof(target));
|
|
dns_name_init(&name);
|
|
dns_name_setbuffer(&name, &b);
|
|
r.base = source;
|
|
r.length = sizeof(source);
|
|
dns_name_fromregion(&name, &r);
|
|
assert_int_equal(9, name.length);
|
|
assert_ptr_equal(target, name.ndata);
|
|
assert_true(dns_name_isabsolute(&name));
|
|
|
|
/*
|
|
* Extract the fully qualified name at the beginning of 'source'
|
|
* into 'name' where 'name.ndata' points to the source.
|
|
*/
|
|
isc_buffer_init(&b, target, sizeof(target));
|
|
dns_name_init(&name);
|
|
r.base = source;
|
|
r.length = sizeof(source);
|
|
dns_name_fromregion(&name, &r);
|
|
assert_int_equal(9, name.length);
|
|
assert_ptr_equal(source, name.ndata);
|
|
assert_true(dns_name_isabsolute(&name));
|
|
|
|
/*
|
|
* Extract the partially qualified name in 'source' into 'name'
|
|
* where 'name.ndata' points to the source.
|
|
*/
|
|
isc_buffer_init(&b, target, sizeof(target));
|
|
dns_name_init(&name);
|
|
r.base = source;
|
|
r.length = 8;
|
|
dns_name_fromregion(&name, &r);
|
|
assert_int_equal(8, name.length);
|
|
assert_ptr_equal(source, name.ndata);
|
|
assert_false(dns_name_isabsolute(&name));
|
|
|
|
/*
|
|
* Extract empty name in 'source' into 'name'.
|
|
*/
|
|
isc_buffer_init(&b, target, sizeof(target));
|
|
dns_name_init(&name);
|
|
r.base = source;
|
|
r.length = 0;
|
|
dns_name_fromregion(&name, &r);
|
|
assert_int_equal(0, name.length);
|
|
assert_ptr_equal(source, name.ndata);
|
|
assert_false(dns_name_isabsolute(&name));
|
|
}
|
|
|
|
/* is trust-anchor-telemetry test */
|
|
ISC_RUN_TEST_IMPL(istat) {
|
|
dns_fixedname_t fixed;
|
|
dns_name_t *name;
|
|
isc_result_t result;
|
|
size_t i;
|
|
struct {
|
|
const char *name;
|
|
bool istat;
|
|
} data[] = { { ".", false },
|
|
{ "_ta-", false },
|
|
{ "_ta-1234", true },
|
|
{ "_TA-1234", true },
|
|
{ "+TA-1234", false },
|
|
{ "_fa-1234", false },
|
|
{ "_td-1234", false },
|
|
{ "_ta_1234", false },
|
|
{ "_ta-g234", false },
|
|
{ "_ta-1h34", false },
|
|
{ "_ta-12i4", false },
|
|
{ "_ta-123j", false },
|
|
{ "_ta-1234-abcf", true },
|
|
{ "_ta-1234-abcf-ED89", true },
|
|
{ "_ta-12345-abcf-ED89", false },
|
|
{ "_ta-.example", false },
|
|
{ "_ta-1234.example", true },
|
|
{ "_ta-1234-abcf.example", true },
|
|
{ "_ta-1234-abcf-ED89.example", true },
|
|
{ "_ta-12345-abcf-ED89.example", false },
|
|
{ "_ta-1234-abcfe-ED89.example", false },
|
|
{ "_ta-1234-abcf-EcD89.example", false } };
|
|
|
|
UNUSED(state);
|
|
|
|
name = dns_fixedname_initname(&fixed);
|
|
|
|
for (i = 0; i < (sizeof(data) / sizeof(data[0])); i++) {
|
|
result = dns_name_fromstring(name, data[i].name, dns_rootname,
|
|
0, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
assert_int_equal(dns_name_istat(name), data[i].istat);
|
|
}
|
|
}
|
|
|
|
static bool
|
|
name_attr_zero(struct dns_name_attrs attributes) {
|
|
return !(attributes.absolute | attributes.readonly |
|
|
attributes.dynamic | attributes.nocompress | attributes.cache |
|
|
attributes.answer | attributes.ncache | attributes.chaining |
|
|
attributes.chase | attributes.wildcard |
|
|
attributes.prerequisite | attributes.update |
|
|
attributes.hasupdaterec);
|
|
}
|
|
|
|
/* dns_name_init */
|
|
ISC_RUN_TEST_IMPL(init) {
|
|
dns_name_t name;
|
|
|
|
dns_name_init(&name);
|
|
|
|
assert_null(name.ndata);
|
|
assert_int_equal(name.length, 0);
|
|
assert_null(name.buffer);
|
|
assert_true(name_attr_zero(name.attributes));
|
|
}
|
|
|
|
/* dns_name_invalidate */
|
|
ISC_RUN_TEST_IMPL(invalidate) {
|
|
dns_name_t name;
|
|
|
|
dns_name_init(&name);
|
|
dns_name_invalidate(&name);
|
|
|
|
assert_null(name.ndata);
|
|
assert_int_equal(name.length, 0);
|
|
assert_null(name.buffer);
|
|
assert_true(name_attr_zero(name.attributes));
|
|
}
|
|
|
|
/* dns_name_setbuffer/hasbuffer */
|
|
ISC_RUN_TEST_IMPL(buffer) {
|
|
dns_name_t name;
|
|
unsigned char buf[BUFSIZ];
|
|
isc_buffer_t b;
|
|
|
|
UNUSED(state);
|
|
|
|
isc_buffer_init(&b, buf, BUFSIZ);
|
|
dns_name_init(&name);
|
|
dns_name_setbuffer(&name, &b);
|
|
assert_ptr_equal(name.buffer, &b);
|
|
assert_true(dns_name_hasbuffer(&name));
|
|
}
|
|
|
|
/* dns_name_isabsolute */
|
|
ISC_RUN_TEST_IMPL(isabsolute) {
|
|
struct {
|
|
const char *namestr;
|
|
bool expect;
|
|
} testcases[] = { { "x", false },
|
|
{ "a.b.c.d.", true },
|
|
{ "x.z", false } };
|
|
unsigned int i;
|
|
|
|
UNUSED(state);
|
|
|
|
for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
|
|
isc_result_t result;
|
|
dns_name_t name;
|
|
unsigned char data[BUFSIZ];
|
|
isc_buffer_t b, nb;
|
|
size_t len;
|
|
|
|
len = strlen(testcases[i].namestr);
|
|
isc_buffer_constinit(&b, testcases[i].namestr, len);
|
|
isc_buffer_add(&b, len);
|
|
|
|
dns_name_init(&name);
|
|
isc_buffer_init(&nb, data, BUFSIZ);
|
|
dns_name_setbuffer(&name, &nb);
|
|
result = dns_name_fromtext(&name, &b, NULL, 0);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
assert_int_equal(dns_name_isabsolute(&name),
|
|
testcases[i].expect);
|
|
}
|
|
}
|
|
|
|
/* dns_name_hash */
|
|
ISC_RUN_TEST_IMPL(hash) {
|
|
struct {
|
|
const char *name1;
|
|
const char *name2;
|
|
bool expect;
|
|
bool expecti;
|
|
} testcases[] = {
|
|
{ "a.b.c.d", "A.B.C.D", true, false },
|
|
{ "a.b.c.d.", "A.B.C.D.", true, false },
|
|
{ "a.b.c.d", "a.b.c.d", true, true },
|
|
{ "A.B.C.D.", "A.B.C.D.", true, false },
|
|
{ "x.y.z.w", "a.b.c.d", false, false },
|
|
{ "x.y.z.w.", "a.b.c.d.", false, false },
|
|
};
|
|
unsigned int i;
|
|
|
|
UNUSED(state);
|
|
|
|
for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
|
|
isc_result_t result;
|
|
dns_fixedname_t f1, f2;
|
|
dns_name_t *n1, *n2;
|
|
unsigned int h1, h2;
|
|
|
|
n1 = dns_fixedname_initname(&f1);
|
|
n2 = dns_fixedname_initname(&f2);
|
|
|
|
result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
/* Check case-insensitive hashing first */
|
|
h1 = dns_name_hash(n1);
|
|
h2 = dns_name_hash(n2);
|
|
|
|
if (verbose) {
|
|
print_message("# %s hashes to %u, "
|
|
"%s to %u, case insensitive\n",
|
|
testcases[i].name1, h1,
|
|
testcases[i].name2, h2);
|
|
}
|
|
|
|
assert_int_equal((h1 == h2), testcases[i].expect);
|
|
|
|
/* Now case-sensitive */
|
|
h1 = dns_name_hash(n1);
|
|
h2 = dns_name_hash(n2);
|
|
|
|
if (verbose) {
|
|
print_message("# %s hashes to %u, "
|
|
"%s to %u, case sensitive\n",
|
|
testcases[i].name1, h1,
|
|
testcases[i].name2, h2);
|
|
}
|
|
|
|
assert_int_equal((h1 == h2), testcases[i].expect);
|
|
}
|
|
}
|
|
|
|
/* dns_name_issubdomain */
|
|
ISC_RUN_TEST_IMPL(issubdomain) {
|
|
struct {
|
|
const char *name1;
|
|
const char *name2;
|
|
bool expect;
|
|
} testcases[] = {
|
|
{ "c.d", "a.b.c.d", false }, { "c.d.", "a.b.c.d.", false },
|
|
{ "b.c.d", "c.d", true }, { "a.b.c.d.", "c.d.", true },
|
|
{ "a.b.c", "a.b.c", true }, { "a.b.c.", "a.b.c.", true },
|
|
{ "x.y.z", "a.b.c", false }
|
|
};
|
|
unsigned int i;
|
|
|
|
UNUSED(state);
|
|
|
|
for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
|
|
isc_result_t result;
|
|
dns_fixedname_t f1, f2;
|
|
dns_name_t *n1, *n2;
|
|
|
|
n1 = dns_fixedname_initname(&f1);
|
|
n2 = dns_fixedname_initname(&f2);
|
|
|
|
result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
if (verbose) {
|
|
print_message("# check: %s %s a subdomain of %s\n",
|
|
testcases[i].name1,
|
|
testcases[i].expect ? "is" : "is not",
|
|
testcases[i].name2);
|
|
}
|
|
|
|
assert_int_equal(dns_name_issubdomain(n1, n2),
|
|
testcases[i].expect);
|
|
}
|
|
}
|
|
|
|
/* dns_name_countlabels */
|
|
ISC_RUN_TEST_IMPL(countlabels) {
|
|
struct {
|
|
const char *namestr;
|
|
unsigned int expect;
|
|
} testcases[] = {
|
|
{ "c.d", 2 },
|
|
{ "c.d.", 3 },
|
|
{ "a.b.c.d.", 5 },
|
|
{ "a.b.c.d", 4 },
|
|
{ "a.b.c", 3 },
|
|
{ ".", 1 },
|
|
{ "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.",
|
|
128 },
|
|
};
|
|
unsigned int i;
|
|
|
|
UNUSED(state);
|
|
|
|
for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
|
|
isc_result_t result;
|
|
dns_fixedname_t fname;
|
|
dns_name_t *name;
|
|
|
|
name = dns_fixedname_initname(&fname);
|
|
|
|
result = dns_name_fromstring(name, testcases[i].namestr, NULL,
|
|
0, NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
if (verbose) {
|
|
print_message("# %s: expect %u labels\n",
|
|
testcases[i].namestr,
|
|
testcases[i].expect);
|
|
}
|
|
|
|
assert_int_equal(dns_name_countlabels(name),
|
|
testcases[i].expect);
|
|
}
|
|
}
|
|
|
|
/* dns_name_getlabel */
|
|
ISC_RUN_TEST_IMPL(getlabel) {
|
|
struct {
|
|
const char *name1;
|
|
unsigned int pos1;
|
|
const char *name2;
|
|
unsigned int pos2;
|
|
} testcases[] = {
|
|
{ "c.d", 1, "a.b.c.d", 3 },
|
|
{ "a.b.c.d", 3, "c.d", 1 },
|
|
{ "a.b.c.", 3, "A.B.C.", 3 },
|
|
};
|
|
unsigned int i;
|
|
|
|
UNUSED(state);
|
|
|
|
for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
|
|
isc_result_t result;
|
|
dns_fixedname_t f1, f2;
|
|
dns_name_t *n1, *n2;
|
|
dns_label_t l1, l2;
|
|
unsigned int j;
|
|
|
|
n1 = dns_fixedname_initname(&f1);
|
|
n2 = dns_fixedname_initname(&f2);
|
|
|
|
result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
dns_name_getlabel(n1, testcases[i].pos1, &l1);
|
|
dns_name_getlabel(n2, testcases[i].pos2, &l2);
|
|
assert_int_equal(l1.length, l2.length);
|
|
|
|
for (j = 0; j < l1.length; j++) {
|
|
assert_int_equal(l1.base[j], l2.base[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* dns_name_getlabelsequence */
|
|
ISC_RUN_TEST_IMPL(getlabelsequence) {
|
|
struct {
|
|
const char *name1;
|
|
unsigned int pos1;
|
|
const char *name2;
|
|
unsigned int pos2;
|
|
unsigned int range;
|
|
} testcases[] = {
|
|
{ "c.d", 1, "a.b.c.d", 3, 1 },
|
|
{ "a.b.c.d.e", 2, "c.d", 0, 2 },
|
|
{ "a.b.c", 0, "a.b.c", 0, 3 },
|
|
};
|
|
unsigned int i;
|
|
|
|
UNUSED(state);
|
|
|
|
for (i = 0; i < (sizeof(testcases) / sizeof(testcases[0])); i++) {
|
|
isc_result_t result;
|
|
dns_name_t t1, t2;
|
|
dns_fixedname_t f1, f2;
|
|
dns_name_t *n1, *n2;
|
|
|
|
/* target names */
|
|
dns_name_init(&t1);
|
|
dns_name_init(&t2);
|
|
|
|
/* source names */
|
|
n1 = dns_fixedname_initname(&f1);
|
|
n2 = dns_fixedname_initname(&f2);
|
|
|
|
result = dns_name_fromstring(n1, testcases[i].name1, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
result = dns_name_fromstring(n2, testcases[i].name2, NULL, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
dns_name_getlabelsequence(n1, testcases[i].pos1,
|
|
testcases[i].range, &t1);
|
|
dns_name_getlabelsequence(n2, testcases[i].pos2,
|
|
testcases[i].range, &t2);
|
|
|
|
assert_true(dns_name_equal(&t1, &t2));
|
|
}
|
|
}
|
|
|
|
ISC_RUN_TEST_IMPL(maxlabels) {
|
|
isc_result_t result;
|
|
dns_fixedname_t fixed;
|
|
dns_name_t *name = NULL;
|
|
|
|
const char one_too_many[] =
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y."
|
|
"a.b.c.";
|
|
|
|
name = dns_fixedname_initname(&fixed);
|
|
result = dns_name_fromstring(name, one_too_many, dns_rootname, 0, NULL);
|
|
assert_int_equal(result, ISC_R_NOSPACE);
|
|
|
|
name = dns_fixedname_initname(&fixed);
|
|
result = dns_name_fromstring(name, one_too_many + 2, dns_rootname, 0,
|
|
NULL);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
assert_true(dns_name_isvalid(name));
|
|
assert_int_equal(dns_name_countlabels(name), DNS_NAME_MAXLABELS);
|
|
}
|
|
|
|
#ifdef DNS_BENCHMARK_TESTS
|
|
|
|
/*
|
|
* XXXMUKS: Don't delete this code. It is useful in benchmarking the
|
|
* name parser, but we don't require it as part of the unit test runs.
|
|
*/
|
|
|
|
/* Benchmark dns_name_fromwire() implementation */
|
|
|
|
ISC_RUN_TEST_IMPL(fromwire_thread(void *arg) {
|
|
unsigned int maxval = 32000000;
|
|
uint8_t data[] = { 3, 'w', 'w', 'w', 7, 'e', 'x',
|
|
'a', 'm', 'p', 'l', 'e', 7, 'i',
|
|
'n', 'v', 'a', 'l', 'i', 'd', 0 };
|
|
unsigned char output_data[DNS_NAME_MAXWIRE];
|
|
isc_buffer_t source, target;
|
|
unsigned int i;
|
|
dns_decompress_t dctx;
|
|
|
|
UNUSED(arg);
|
|
|
|
dns_decompress_init(&dctx, DNS_DECOMPRESS_STRICT);
|
|
dns_decompress_setmethods(&dctx, DNS_COMPRESS_NONE);
|
|
|
|
isc_buffer_init(&source, data, sizeof(data));
|
|
isc_buffer_add(&source, sizeof(data));
|
|
isc_buffer_init(&target, output_data, sizeof(output_data));
|
|
|
|
/* Parse 32 million names in each thread */
|
|
for (i = 0; i < maxval; i++) {
|
|
dns_name_t name;
|
|
|
|
isc_buffer_clear(&source);
|
|
isc_buffer_clear(&target);
|
|
isc_buffer_add(&source, sizeof(data));
|
|
isc_buffer_setactive(&source, sizeof(data));
|
|
|
|
dns_name_init(&name, NULL);
|
|
(void)dns_name_fromwire(&name, &source, &dctx, &target);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ISC_RUN_TEST_IMPL(benchmark) {
|
|
isc_result_t result;
|
|
unsigned int i;
|
|
isc_time_t ts1, ts2;
|
|
double t;
|
|
unsigned int nthreads;
|
|
isc_thread_t threads[32];
|
|
|
|
UNUSED(state);
|
|
|
|
debug_mem_record = false;
|
|
|
|
result = isc_time_now(&ts1);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
nthreads = ISC_MIN(isc_os_ncpus(), 32);
|
|
nthreads = ISC_MAX(nthreads, 1);
|
|
for (i = 0; i < nthreads; i++) {
|
|
isc_thread_create(fromwire_thread, NULL, &threads[i]);
|
|
}
|
|
|
|
for (i = 0; i < nthreads; i++) {
|
|
isc_thread_join(threads[i], NULL);
|
|
}
|
|
|
|
result = isc_time_now(&ts2);
|
|
assert_int_equal(result, ISC_R_SUCCESS);
|
|
|
|
t = isc_time_microdiff(&ts2, &ts1);
|
|
|
|
printf("%u dns_name_fromwire() calls, %f seconds, %f calls/second\n",
|
|
nthreads * 32000000, t / 1000000.0,
|
|
(nthreads * 32000000) / (t / 1000000.0));
|
|
}
|
|
|
|
#endif /* DNS_BENCHMARK_TESTS */
|
|
|
|
ISC_TEST_LIST_START
|
|
ISC_TEST_ENTRY(fullcompare)
|
|
ISC_TEST_ENTRY(compression)
|
|
ISC_TEST_ENTRY(collision)
|
|
ISC_TEST_ENTRY(fromregion)
|
|
ISC_TEST_ENTRY(istat)
|
|
ISC_TEST_ENTRY(init)
|
|
ISC_TEST_ENTRY(invalidate)
|
|
ISC_TEST_ENTRY(buffer)
|
|
ISC_TEST_ENTRY(isabsolute)
|
|
ISC_TEST_ENTRY(hash)
|
|
ISC_TEST_ENTRY(issubdomain)
|
|
ISC_TEST_ENTRY(countlabels)
|
|
ISC_TEST_ENTRY(getlabel)
|
|
ISC_TEST_ENTRY(getlabelsequence)
|
|
ISC_TEST_ENTRY(maxlabels)
|
|
#ifdef DNS_BENCHMARK_TESTS
|
|
ISC_TEST_ENTRY(benchmark)
|
|
#endif /* DNS_BENCHMARK_TESTS */
|
|
ISC_TEST_LIST_END
|
|
|
|
ISC_TEST_MAIN
|