diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index c88800cbdf..ece4ae89f0 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -387,6 +387,34 @@ dns_name_compare(dns_name_t *name1, dns_name_t *name2); * 1 'name1' is greater than 'name2' */ +isc_boolean_t +dns_name_equal(dns_name_t *name1, dns_name_t *name2); +/* + * Are 'name1' and 'name2' equal? + * + * Notes: + * Because it only needs to test for equality, dns_name_equal() can be + * significantly faster than dns_name_fullcompare() or dns_name_compare(). + * + * Offsets tables are not used in the comparision. + * + * It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + * + * Requires: + * 'name1' is a valid name + * + * 'name2' is a valid name + * + * Either name1 is absolute and name2 is absolute, or neither is. + * + * Returns: + * ISC_TRUE 'name1' and 'name2' are equal + * ISC_FALSE 'name1' and 'name2' are not equal + */ + int dns_name_rdatacompare(dns_name_t *name1, dns_name_t *name2); /* diff --git a/lib/dns/name.c b/lib/dns/name.c index 69c1d74421..cbcd5323ae 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -413,8 +413,8 @@ dns_name_fullcompare(dns_name_t *name1, dns_name_t *name2, /* * Either name1 is absolute and name2 is absolute, or neither is. */ - REQUIRE(((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ^ - (name2->attributes & DNS_NAMEATTR_ABSOLUTE)) == 0); + REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == + (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); SETUP_OFFSETS(name1, offsets1, odata1); SETUP_OFFSETS(name2, offsets2, odata2); @@ -606,6 +606,72 @@ dns_name_compare(dns_name_t *name1, dns_name_t *name2) { return (order); } +isc_boolean_t +dns_name_equal(dns_name_t *name1, dns_name_t *name2) { + unsigned int l, count; + unsigned char c; + unsigned char *label1, *label2; + + /* + * Are 'name1' and 'name2' equal? + * + * Note: It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + */ + + REQUIRE(VALID_NAME(name1)); + REQUIRE(VALID_NAME(name2)); + /* + * Either name1 is absolute and name2 is absolute, or neither is. + */ + REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) == + (name2->attributes & DNS_NAMEATTR_ABSOLUTE)); + + if (name1->length != name2->length) + return (ISC_FALSE); + + l = name1->labels; + + if (l != name2->labels) + return (ISC_FALSE); + + label1 = name1->ndata; + label2 = name2->ndata; + while (l > 0) { + l--; + count = *label1++; + if (count != *label2++) + return (ISC_FALSE); + if (count <= 63) { + while (count > 0) { + count--; + c = maptolower[*label1++]; + if (c != maptolower[*label2++]) + return (ISC_FALSE); + } + } else { + INSIST(count == DNS_LABELTYPE_BITSTRING); + count = *label1++; + if (count != *label2++) + return (ISC_FALSE); + if (count == 0) + count = 256; + /* number of bytes */ + count = (count + 7) / 8; + while (count > 0) { + count--; + c = *label1++; + if (c != *label2++) + return (ISC_FALSE); + } + } + } + + return (ISC_TRUE); +} + int dns_name_rdatacompare(dns_name_t *name1, dns_name_t *name2) { unsigned int l1, l2, l, count1, count2, count; @@ -665,6 +731,7 @@ dns_name_rdatacompare(dns_name_t *name1, dns_name_t *name2) { /* number of bytes */ count = (count1 + 7) / 8; while (count > 0) { + count--; c1 = *label1++; c2 = *label2++; if (c1 != c2)