3306. [bug] Improve DNS64 reverse zone performance. [RT #28563]

3305.   [func]          Add wire format lookup method to sdb. [RT #28563]
This commit is contained in:
Mark Andrews 2012-04-11 12:20:44 +10:00
parent e3a1a68c1b
commit 74ce4de82e
6 changed files with 234 additions and 106 deletions

View file

@ -1,3 +1,7 @@
3306. [bug] Improve DNS64 reverse zone performance. [RT #28563]
3305. [func] Add wire format lookup method to sdb. [RT #28563]
3304. [bug] Use hmctx, not mctx when freeing rbtdb->heaps. [RT #28571]
3303. [bug] named could die when reloading. [RT #28606]

View file

@ -69,35 +69,79 @@ static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL };
static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL };
static dns_sdbimplementation_t *builtin_impl;
static dns_sdbimplementation_t *dns64_impl;
static const char hex[] = "0123456789abcdef";
static const char HEX[] = "0123456789ABCDEF";
/*
* Pre computed HEX * 16 or 1 table.
*/
static const unsigned char hex16[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*00*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*20*/
0, 16, 32, 48, 64, 80, 96,112,128,144, 1, 1, 1, 1, 1, 1, /*30*/
1,160,176,192,208,224,240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/
1,160,176,192,208,224,240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /*F0*/
};
const unsigned char decimal[] = "0123456789";
static size_t
dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
size_t i, j = 0;
for (i = 0; i < 4; i++) {
unsigned char c = v[start++];
if (start == 7)
start++;
if (c > 99) {
rdata[j++] = 3;
rdata[j++] = decimal[c/100]; c = c % 100;
rdata[j++] = decimal[c/10]; c = c % 10;
rdata[j++] = decimal[c];
} else if (c > 9) {
rdata[j++] = 2;
rdata[j++] = decimal[c/10]; c = c % 10;
rdata[j++] = decimal[c];
} else {
rdata[j++] = 1;
rdata[j++] = decimal[c];
}
}
memcpy(&rdata[j], "\07in-addr\04arpa", 14);
return (j + 14);
}
static isc_result_t
dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) {
size_t zlen, nlen, j;
const char *s;
unsigned char v[16];
dns64_cname(const dns_name_t *zone, const dns_name_t *name,
dns_sdblookup_t *lookup)
{
size_t zlen, nlen, j, len;
unsigned char v[16], n;
unsigned int i;
char reverse[sizeof("123.123.123.123.in-addr.arpa.")];
unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
unsigned char *ndata;
/*
* The sum the length of the relative name and the length of the zone
* name for a IPv6 reverse lookup comes to 71.
* The combined length of the zone and name is 74.
*
* The reverse of 2001::10.0.0.1 (dns64 2001::/96) has a zone of
* "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2.ip6.arpa"
* and a name of "1.0.0.0.0.0.a.0". The sum of the lengths of these
* two strings is 71.
* The minimum zone length is 10 ((3)ip6(4)arpa(0)).
*
* The minimum length for a ip6.arpa zone name is 8.
*
* The length of name should always be odd as we are expecting
* The length of name should always be even as we are expecting
* a series of nibbles.
*/
zlen = strlen(zone);
nlen = strlen(name);
if ((zlen + nlen) > 71U || zlen < 8U || (nlen % 2) != 1U)
zlen = zone->length;
nlen = name->length;
if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U)
return (ISC_R_NOTFOUND);
/*
@ -116,25 +160,20 @@ dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) {
* are byte aligned and we correctly return ISC_R_NOTFOUND or
* ISC_R_SUCCESS. We will not generate a CNAME in this case.
*/
i = (nlen % 4) == 1U ? 1 : 0;
ndata = name->ndata;
i = (nlen % 4) == 2U ? 1 : 0;
j = nlen;
memset(v, 0, sizeof(v));
while (j >= 1U) {
while (j != 0) {
INSIST((i/2) < sizeof(v));
if (j > 1U && name[1] != '.')
if (ndata[0] != 1)
return (ISC_R_NOTFOUND);
v[i/2] >>= 4;
if ((s = strchr(hex, name[0])) != NULL)
v[i/2] |= (s - hex) << 4;
else if ((s = strchr(HEX, name[0])) != NULL)
v[i/2] |= (s - HEX) << 4;
else
n = hex16[ndata[1]&0xff];
if (n == 1)
return (ISC_R_NOTFOUND);
if (j > 1U)
j -= 2;
else
j -= 1;
name += 2;
v[i/2] = n | (v[i/2]>>4);
j -= 2;
ndata += 2;
i++;
}
@ -144,90 +183,91 @@ dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) {
* it corresponds to a empty node in the zone or there should be
* a CNAME.
*/
#define ZLEN(x) (10 + (x)/2)
switch (zlen) {
case 24: /* prefix len 32 */
/*
* If the total length is not 71 then this is a empty node
* so return success.
*/
if (nlen + zlen != 71U)
return (ISC_R_SUCCESS);
snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
v[8], v[9], v[10], v[11]);
break;
case 28: /* prefix len 40 */
case ZLEN(32): /* prefix len 32 */
/*
* The nibbles that map to this byte must be zero for 'name'
* to exist in the zone.
*/
if (nlen > 11U && v[nlen/4 - 3] != 0)
if (nlen > 16U && v[(nlen-1)/4 - 4] != 0)
return (ISC_R_NOTFOUND);
/*
* If the total length is not 71 then this is a empty node
* If the total length is not 74 then this is a empty node
* so return success.
*/
if (nlen + zlen != 71U)
if (nlen + zlen != 74U)
return (ISC_R_SUCCESS);
snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
v[6], v[8], v[9], v[10]);
len = dns64_rdata(v, 8, rdata);
break;
case 32: /* prefix len 48 */
case ZLEN(40): /* prefix len 40 */
/*
* The nibbles that map to this byte must be zero for 'name'
* to exist in the zone.
*/
if (nlen > 7U && v[nlen/4 - 2] != 0)
if (nlen > 12U && v[(nlen-1)/4 - 3] != 0)
return (ISC_R_NOTFOUND);
/*
* If the total length is not 71 then this is a empty node
* If the total length is not 74 then this is a empty node
* so return success.
*/
if (nlen + zlen != 71U)
if (nlen + zlen != 74U)
return (ISC_R_SUCCESS);
snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
v[5], v[6], v[8], v[9]);
len = dns64_rdata(v, 6, rdata);
break;
case 36: /* prefix len 56 */
case ZLEN(48): /* prefix len 48 */
/*
* The nibbles that map to this byte must be zero for 'name'
* to exist in the zone.
*/
if (nlen > 3U && v[nlen/4 - 1] != 0)
if (nlen > 8U && v[(nlen-1)/4 - 2] != 0)
return (ISC_R_NOTFOUND);
/*
* If the total length is not 71 then this is a empty node
* If the total length is not 74 then this is a empty node
* so return success.
*/
if (nlen + zlen != 71U)
if (nlen + zlen != 74U)
return (ISC_R_SUCCESS);
snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
v[4], v[5], v[6], v[8]);
len = dns64_rdata(v, 5, rdata);
break;
case 40: /* prefix len 64 */
case ZLEN(56): /* prefix len 56 */
/*
* The nibbles that map to this byte must be zero for 'name'
* to exist in the zone.
*/
if (v[nlen/4] != 0)
if (nlen > 4U && v[(nlen-1)/4 - 1] != 0)
return (ISC_R_NOTFOUND);
/*
* If the total length is not 71 then this is a empty node
* If the total length is not 74 then this is a empty node
* so return success.
*/
if (nlen + zlen != 71U)
if (nlen + zlen != 74U)
return (ISC_R_SUCCESS);
snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
v[3], v[4], v[5], v[6]);
len = dns64_rdata(v, 4, rdata);
break;
case 56: /* prefix len 96 */
case ZLEN(64): /* prefix len 64 */
/*
* If the total length is not 71 then this is a empty node
* The nibbles that map to this byte must be zero for 'name'
* to exist in the zone.
*/
if (v[(nlen-1)/4] != 0)
return (ISC_R_NOTFOUND);
/*
* If the total length is not 74 then this is a empty node
* so return success.
*/
if (nlen + zlen != 71U)
if (nlen + zlen != 74U)
return (ISC_R_SUCCESS);
snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
v[0], v[1], v[2], v[3]);
len = dns64_rdata(v, 3, rdata);
break;
case ZLEN(96): /* prefix len 96 */
/*
* If the total length is not 74 then this is a empty node
* so return success.
*/
if (nlen + zlen != 74U)
return (ISC_R_SUCCESS);
len = dns64_rdata(v, 0, rdata);
break;
default:
/*
@ -236,7 +276,7 @@ dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) {
*/
return (ISC_R_NOTFOUND);
}
return (dns_sdb_putrr(lookup, "CNAME", 600, reverse));
return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600, rdata, len));
}
static isc_result_t
@ -252,12 +292,26 @@ builtin_lookup(const char *zone, const char *name, void *dbdata,
if (strcmp(name, "@") == 0)
return (b->do_lookup(lookup));
else if (b->do_lookup == do_dns64_lookup)
return (dns64_cname(zone, name, lookup));
else
return (ISC_R_NOTFOUND);
}
static isc_result_t
dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo)
{
builtin_t *b = (builtin_t *) dbdata;
UNUSED(methods);
UNUSED(clientinfo);
if (name->labels == 0 && name->length == 0)
return (b->do_lookup(lookup));
else
return (dns64_cname(zone, name, lookup));
}
static isc_result_t
put_txt(dns_sdblookup_t *lookup, const char *text) {
unsigned char buf[256];
@ -486,7 +540,17 @@ static dns_sdbmethods_t builtin_methods = {
builtin_authority,
NULL, /* allnodes */
builtin_create,
builtin_destroy
builtin_destroy,
NULL
};
static dns_sdbmethods_t dns64_methods = {
NULL,
builtin_authority,
NULL, /* allnodes */
builtin_create,
builtin_destroy,
dns64_lookup,
};
isc_result_t
@ -496,11 +560,17 @@ ns_builtin_init(void) {
DNS_SDBFLAG_RELATIVERDATA,
ns_g_mctx, &builtin_impl)
== ISC_R_SUCCESS);
RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
DNS_SDBFLAG_RELATIVEOWNER |
DNS_SDBFLAG_RELATIVERDATA |
DNS_SDBFLAG_DNS64,
ns_g_mctx, &dns64_impl)
== ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
}
void
ns_builtin_deinit(void) {
dns_sdb_unregister(&builtin_impl);
dns_sdb_unregister(&dns64_impl);
}

View file

@ -1368,7 +1368,7 @@ dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
{
char *cp;
char reverse[48+sizeof("ip6.arpa.")];
const char *dns64_dbtype[4] = { "_builtin", "dns64", ".", "." };
const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
const char *sep = ": view ";
const char *viewname = view->name;
const unsigned char *s6;

View file

@ -1264,6 +1264,23 @@ do
status=`expr $status + $ret`
done
rev=`$ARPANAME 2001:aaaa::10.0.0.1`
regex='..\(.*.IP6.ARPA\)'
rev=`expr "${rev}" : "${regex}"`
fin=`expr "${rev}" : "............${regex}"`
while test "${rev}" != "${fin}"
do
ret=0
echo "I: checking $rev ($n)"
$DIG $DIGOPTS $rev ptr @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep -i "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
grep -i "ANSWER: 0," dig.out.ns2.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
rev=`expr "${rev}" : "${regex}"`
done
echo "I: checking dns64-server and dns64-contact ($n)"
$DIG $DIGOPTS soa 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.a.a.a.1.0.0.2.ip6.arpa @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "SOA.dns64.example.net..hostmaster.example.net." dig.out.ns2.test$n > /dev/null || ret=1

View file

@ -62,7 +62,12 @@ typedef isc_result_t
dns_sdblookup_t *lookup,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo);
typedef isc_result_t
(*dns_sdblookup2func_t)(const dns_name_t *zone, const dns_name_t *name,
void *dbdata, dns_sdblookup_t *lookup,
dns_clientinfomethods_t *methods,
dns_clientinfo_t *clientinfo);
typedef isc_result_t
(*dns_sdbauthorityfunc_t)(const char *zone, void *dbdata, dns_sdblookup_t *);
@ -84,6 +89,7 @@ typedef struct dns_sdbmethods {
dns_sdballnodesfunc_t allnodes;
dns_sdbcreatefunc_t create;
dns_sdbdestroyfunc_t destroy;
dns_sdblookup2func_t lookup2;
} dns_sdbmethods_t;
/***
@ -95,6 +101,7 @@ ISC_LANG_BEGINDECLS
#define DNS_SDBFLAG_RELATIVEOWNER 0x00000001U
#define DNS_SDBFLAG_RELATIVERDATA 0x00000002U
#define DNS_SDBFLAG_THREADSAFE 0x00000004U
#define DNS_SDBFLAG_DNS64 0x00000008U
isc_result_t
dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,

View file

@ -216,12 +216,13 @@ dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
REQUIRE(drivername != NULL);
REQUIRE(methods != NULL);
REQUIRE(methods->lookup != NULL);
REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
REQUIRE(mctx != NULL);
REQUIRE(sdbimp != NULL && *sdbimp == NULL);
REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
DNS_SDBFLAG_RELATIVERDATA |
DNS_SDBFLAG_THREADSAFE)) == 0);
DNS_SDBFLAG_THREADSAFE|
DNS_SDBFLAG_DNS64)) == 0);
imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
if (imp == NULL)
@ -280,8 +281,9 @@ initial_size(unsigned int len) {
}
isc_result_t
dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl,
const unsigned char *rdatap, unsigned int rdlen)
dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
dns_ttl_t ttl, const unsigned char *rdatap,
unsigned int rdlen)
{
dns_rdatalist_t *rdatalist;
dns_rdata_t *rdata;
@ -338,7 +340,6 @@ dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl
return (result);
}
isc_result_t
dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
const char *data)
@ -738,6 +739,8 @@ findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
char namestr[DNS_NAME_MAXTEXT + 1];
isc_boolean_t isorigin;
dns_sdbimplementation_t *imp;
dns_name_t relname;
unsigned int labels;
REQUIRE(VALID_SDB(sdb));
REQUIRE(create == ISC_FALSE);
@ -748,34 +751,47 @@ findnodeext(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
imp = sdb->implementation;
isc_buffer_init(&b, namestr, sizeof(namestr));
if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
dns_name_t relname;
unsigned int labels;
isorigin = dns_name_equal(name, &sdb->common.origin);
labels = dns_name_countlabels(name) -
dns_name_countlabels(&db->origin);
dns_name_init(&relname, NULL);
dns_name_getlabelsequence(name, 0, labels, &relname);
result = dns_name_totext(&relname, ISC_TRUE, &b);
if (result != ISC_R_SUCCESS)
return (result);
if (imp->methods->lookup2 != NULL) {
if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
labels = dns_name_countlabels(name) -
dns_name_countlabels(&db->origin);
dns_name_init(&relname, NULL);
dns_name_getlabelsequence(name, 0, labels, &relname);
name = &relname;
}
} else {
result = dns_name_totext(name, ISC_TRUE, &b);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_init(&b, namestr, sizeof(namestr));
if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
labels = dns_name_countlabels(name) -
dns_name_countlabels(&db->origin);
dns_name_init(&relname, NULL);
dns_name_getlabelsequence(name, 0, labels, &relname);
result = dns_name_totext(&relname, ISC_TRUE, &b);
if (result != ISC_R_SUCCESS)
return (result);
} else {
result = dns_name_totext(name, ISC_TRUE, &b);
if (result != ISC_R_SUCCESS)
return (result);
}
isc_buffer_putuint8(&b, 0);
}
isc_buffer_putuint8(&b, 0);
result = createnode(sdb, &node);
if (result != ISC_R_SUCCESS)
return (result);
isorigin = dns_name_equal(name, &sdb->common.origin);
MAYBE_LOCK(sdb);
result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
node, methods, clientinfo);
if (imp->methods->lookup2 != NULL)
result = imp->methods->lookup2(&sdb->common.origin, name,
sdb->dbdata, node, methods,
clientinfo);
else
result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
node, methods, clientinfo);
MAYBE_UNLOCK(sdb);
if (result != ISC_R_SUCCESS &&
!(result == ISC_R_NOTFOUND &&
@ -814,13 +830,13 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
unsigned int nlabels, olabels;
isc_result_t result;
unsigned int i;
unsigned int flags;
REQUIRE(VALID_SDB(sdb));
REQUIRE(nodep == NULL || *nodep == NULL);
REQUIRE(version == NULL || version == (void *) &dummy);
UNUSED(options);
UNUSED(sdb);
if (!dns_name_issubdomain(name, &db->origin))
return (DNS_R_NXDOMAIN);
@ -837,8 +853,9 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
}
result = DNS_R_NXDOMAIN;
for (i = olabels; i <= nlabels; i++) {
flags = sdb->implementation->flags;
i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
for (; i <= nlabels; i++) {
/*
* Look up the next label.
*/
@ -857,6 +874,18 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
if (result != ISC_R_SUCCESS)
return (result);
/*
* DNS64 zone's don't have DNAME or NS records.
*/
if ((flags & DNS_SDBFLAG_DNS64) != 0)
goto skip;
/*
* DNS64 zone's don't have DNAME or NS records.
*/
if ((flags & DNS_SDBFLAG_DNS64) != 0)
goto skip;
/*
* Look for a DNAME at the current label, unless this is
* the qname.
@ -906,6 +935,7 @@ findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
continue;
}
skip:
/*
* If we're looking for ANY, we're done.
*/