From a8da00ef95ba37b9d071c2b8db1a0c967e060106 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 27 Feb 2015 15:08:38 +1100 Subject: [PATCH] 4079. [func] Preserve the case of the ownername of records to the RRset level. [RT #37442] --- CHANGES | 3 + bin/named/query.c | 4 +- bin/named/update.c | 80 ++++++++++------ bin/tests/system/case/clean.sh | 6 +- bin/tests/system/case/dynamic.good | 6 ++ bin/tests/system/case/ns1/dynamic.db.in | 30 ++++++ bin/tests/system/case/ns1/named.conf | 8 ++ bin/tests/system/case/ns2/named.conf | 6 ++ bin/tests/system/case/postns1.good | 14 +++ bin/tests/system/case/postupdate.good | 6 ++ bin/tests/system/case/setup.sh | 2 + bin/tests/system/case/tests.sh | 80 ++++++++++++++++ lib/dns/compress.c | 41 ++++++-- lib/dns/diff.c | 99 ++++++++++++-------- lib/dns/ecdb.c | 4 +- lib/dns/include/dns/db.h | 4 + lib/dns/include/dns/name.h | 11 ++- lib/dns/include/dns/rdatalist.h | 8 +- lib/dns/include/dns/rdataset.h | 21 ++++- lib/dns/journal.c | 6 +- lib/dns/masterdump.c | 15 ++- lib/dns/message.c | 8 +- lib/dns/name.c | 11 ++- lib/dns/ncache.c | 2 + lib/dns/rbtdb.c | 118 ++++++++++++++++++++++-- lib/dns/rdatalist.c | 51 +++++++++- lib/dns/rdatalist_p.h | 6 ++ lib/dns/rdataset.c | 32 ++++++- lib/dns/rdataslab.c | 2 + lib/dns/rriterator.c | 4 + lib/dns/sdb.c | 2 + lib/dns/sdlz.c | 2 + lib/dns/zone.c | 7 ++ lib/samples/sample-update.c | 3 +- 34 files changed, 593 insertions(+), 109 deletions(-) create mode 100644 bin/tests/system/case/dynamic.good create mode 100644 bin/tests/system/case/ns1/dynamic.db.in create mode 100644 bin/tests/system/case/postns1.good create mode 100644 bin/tests/system/case/postupdate.good create mode 100644 bin/tests/system/case/setup.sh diff --git a/CHANGES b/CHANGES index 676590dbc2..0543e760a5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4079. [func] Preserve the case of the ownername of records to + the RRset level. [RT #37442] + 4078. [bug] Hand the case where CMSG_SPACE(sizeof(int)) != CMSG_SPACE(sizeof(int)). [RT #38621] diff --git a/bin/named/query.c b/bin/named/query.c index ad48585c3b..12e590bce0 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -2380,6 +2380,7 @@ query_dns64(ns_client_t *client, dns_name_t **namep, dns_rdataset_t *rdataset, result = dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset); if (result != ISC_R_SUCCESS) goto cleanup; + dns_rdataset_setownercase(dns64_rdataset, mname); client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; dns64_rdataset->trust = rdataset->trust; query_addrdataset(client, mname, dns64_rdataset); @@ -2514,6 +2515,7 @@ query_filter64(ns_client_t *client, dns_name_t **namep, result = dns_rdatalist_tordataset(myrdatalist, myrdataset); if (result != ISC_R_SUCCESS) goto cleanup; + dns_rdataset_setownercase(myrdataset, name); client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; if (mname == name) { if (dbuf != NULL) @@ -2920,11 +2922,11 @@ query_add_cname(ns_client_t *client, dns_name_t *qname, dns_name_t *tname, rdata->rdclass = client->message->rdclass; rdata->type = dns_rdatatype_cname; - ISC_LIST_INIT(rdatalist->rdata); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS); rdataset->trust = trust; + dns_rdataset_setownercase(rdataset, aname); query_addrrset(client, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER); diff --git a/bin/named/update.c b/bin/named/update.c index 8c2910a63d..52bb22e0a0 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -224,6 +224,28 @@ struct update_event { dns_message_t *answer; }; +/*% + * Prepare an RR for the addition of the new RR 'ctx->update_rr', + * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting + * the RRs if it is replaced by the new RR or has a conflicting TTL. + * The necessary changes are appended to ctx->del_diff and ctx->add_diff; + * we need to do all deletions before any additions so that we don't run + * into transient states with conflicting TTLs. + */ + +typedef struct { + dns_db_t *db; + dns_dbversion_t *ver; + dns_diff_t *diff; + dns_name_t *name; + dns_name_t *oldname; + dns_rdata_t *update_rr; + dns_ttl_t update_rr_ttl; + isc_boolean_t ignore_add; + dns_diff_t del_diff; + dns_diff_t add_diff; +} add_rr_prepare_ctx_t; + /**************************************************************************/ /* * Forward declarations. @@ -233,6 +255,7 @@ static void update_action(isc_task_t *task, isc_event_t *event); static void updatedone_action(isc_task_t *task, isc_event_t *event); static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); static void forward_done(isc_task_t *task, isc_event_t *event); +static isc_result_t add_rr_prepare_action(void *data, rr_t *rr); /**************************************************************************/ @@ -636,6 +659,7 @@ foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_clientinfomethods_t cm; dns_clientinfo_t ci; dns_dbversion_t *oldver = NULL; + dns_fixedname_t fixed; dns_clientinfomethods_init(&cm, ns_client_sourceip); @@ -673,6 +697,15 @@ foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, if (result != ISC_R_SUCCESS) goto cleanup_node; + if (rr_action == add_rr_prepare_action) { + add_rr_prepare_ctx_t *ctx = rr_action_data; + + dns_fixedname_init(&fixed); + ctx->oldname = dns_fixedname_name(&fixed); + dns_name_copy(name, ctx->oldname, NULL); + dns_rdataset_getownercase(&rdataset, ctx->oldname); + } + for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) @@ -1290,40 +1323,30 @@ delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver, } /**************************************************************************/ -/*% - * Prepare an RR for the addition of the new RR 'ctx->update_rr', - * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting - * the RRs if it is replaced by the new RR or has a conflicting TTL. - * The necessary changes are appended to ctx->del_diff and ctx->add_diff; - * we need to do all deletions before any additions so that we don't run - * into transient states with conflicting TTLs. - */ - -typedef struct { - dns_db_t *db; - dns_dbversion_t *ver; - dns_diff_t *diff; - dns_name_t *name; - dns_rdata_t *update_rr; - dns_ttl_t update_rr_ttl; - isc_boolean_t ignore_add; - dns_diff_t del_diff; - dns_diff_t add_diff; -} add_rr_prepare_ctx_t; static isc_result_t add_rr_prepare_action(void *data, rr_t *rr) { isc_result_t result = ISC_R_SUCCESS; add_rr_prepare_ctx_t *ctx = data; dns_difftuple_t *tuple = NULL; - isc_boolean_t equal; + isc_boolean_t equal, case_equal, ttl_equal; /* - * If the update RR is a "duplicate" of the update RR, + * Are the new and old cases equal? + */ + case_equal = dns_name_caseequal(ctx->name, ctx->oldname); + + /* + * Are the ttl's equal? + */ + ttl_equal = rr->ttl == ctx->update_rr_ttl; + + /* + * If the update RR is a "duplicate" of a existing RR, * the update should be silently ignored. */ equal = ISC_TF(dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0); - if (equal && rr->ttl == ctx->update_rr_ttl) { + if (equal && case_equal && ttl_equal) { ctx->ignore_add = ISC_TRUE; return (ISC_R_SUCCESS); } @@ -1334,19 +1357,19 @@ add_rr_prepare_action(void *data, rr_t *rr) { */ if (replaces_p(ctx->update_rr, &rr->rdata)) { CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, - ctx->name, rr->ttl, &rr->rdata, + ctx->oldname, rr->ttl, &rr->rdata, &tuple)); dns_diff_append(&ctx->del_diff, &tuple); return (ISC_R_SUCCESS); } /* - * If this RR differs in TTL from the update RR, - * its TTL must be adjusted. + * If this RR differs in TTL or case from the update RR, + * its TTL and case must be adjusted. */ - if (rr->ttl != ctx->update_rr_ttl) { + if (!ttl_equal || !case_equal) { CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, - ctx->name, rr->ttl, &rr->rdata, + ctx->oldname, rr->ttl, &rr->rdata, &tuple)); dns_diff_append(&ctx->del_diff, &tuple); if (!equal) { @@ -2931,6 +2954,7 @@ update_action(isc_task_t *task, isc_event_t *event) { ctx.ver = ver; ctx.diff = &diff; ctx.name = name; + ctx.oldname = name; ctx.update_rr = &rdata; ctx.update_rr_ttl = ttl; ctx.ignore_add = ISC_FALSE; diff --git a/bin/tests/system/case/clean.sh b/bin/tests/system/case/clean.sh index 756aa7c1c0..04fb4cc8e3 100644 --- a/bin/tests/system/case/clean.sh +++ b/bin/tests/system/case/clean.sh @@ -15,5 +15,9 @@ # PERFORMANCE OF THIS SOFTWARE. rm -f dig.ns*.test* -rm -f ns2/example.bk rm -f ns*/named.lock +rm -f ns1/dynamic.db +rm -f ns1/dynamic.db.jnl +rm -f ns2/dynamic.bk +rm -f ns2/dynamic.bk.jnl +rm -f ns2/example.bk diff --git a/bin/tests/system/case/dynamic.good b/bin/tests/system/case/dynamic.good new file mode 100644 index 0000000000..2e10b64191 --- /dev/null +++ b/bin/tests/system/case/dynamic.good @@ -0,0 +1,6 @@ +DyNaMiC. 300 IN SOA mname1. . 2000042407 20 20 1814400 3600 +DyNaMiC. 300 IN NS ns1.DYNAMIC. +DyNaMiC. 300 IN MX 0 mail.eXaMpLe. +mAiL.DynamiC. 300 IN A 10.53.0.1 +ns1.DYNAMIC. 300 IN A 10.53.0.1 +DyNaMiC. 300 IN SOA mname1. . 2000042407 20 20 1814400 3600 diff --git a/bin/tests/system/case/ns1/dynamic.db.in b/bin/tests/system/case/ns1/dynamic.db.in new file mode 100644 index 0000000000..c6d9af0f8e --- /dev/null +++ b/bin/tests/system/case/ns1/dynamic.db.in @@ -0,0 +1,30 @@ +; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") +; +; Permission to use, copy, modify, and/or distribute this software for any +; purpose with or without fee is hereby granted, provided that the above +; copyright notice and this permission notice appear in all copies. +; +; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +; PERFORMANCE OF THIS SOFTWARE. + + +$TTL 300 ; 5 minutes +$ORIGIN DyNaMiC. +@ IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +$ORIGIN DYNAMIC. + NS ns1 +ns1 A 10.53.0.1 +$ORIGIN DynamiC. +@ MX 0 mail.eXaMpLe. +mAiL A 10.53.0.1 diff --git a/bin/tests/system/case/ns1/named.conf b/bin/tests/system/case/ns1/named.conf index 2fcc608d69..0242728fdc 100644 --- a/bin/tests/system/case/ns1/named.conf +++ b/bin/tests/system/case/ns1/named.conf @@ -33,4 +33,12 @@ options { zone "example" { type master; file "example.db"; + also-notify { 10.53.0.2; }; +}; + +zone "dynamic" { + type master; + file "dynamic.db"; + allow-update { any; }; + also-notify { 10.53.0.2; }; }; diff --git a/bin/tests/system/case/ns2/named.conf b/bin/tests/system/case/ns2/named.conf index f8735c28a7..13ae8a1069 100644 --- a/bin/tests/system/case/ns2/named.conf +++ b/bin/tests/system/case/ns2/named.conf @@ -36,3 +36,9 @@ zone "example" { file "example.bk"; masters { 10.53.0.1; }; }; + +zone "dynamic" { + type slave; + file "dynamic.bk"; + masters { 10.53.0.1; }; +}; diff --git a/bin/tests/system/case/postns1.good b/bin/tests/system/case/postns1.good new file mode 100644 index 0000000000..46bce2e6fd --- /dev/null +++ b/bin/tests/system/case/postns1.good @@ -0,0 +1,14 @@ + +; <<>> DiG 9.11.0pre-alpha <<>> axfr dynamic @10.53.0.1 -p 5300 +;; global options: +cmd +dYNAMIc. 0 IN SOA mname1. . 2000042409 20 20 1814400 3600 +DyNaMiC. 300 IN NS ns1.DYNAMIC. +DyNaMiC. 300 IN MX 0 mail.eXaMpLe. +mAiL.DynamiC. 300 IN A 10.53.0.1 +Ns1.DyNaMIC. 300 IN A 10.53.0.1 +dYNAMIc. 0 IN SOA mname1. . 2000042409 20 20 1814400 3600 +;; Query time: 0 msec +;; SERVER: 10.53.0.1#5300(10.53.0.1) +;; WHEN: Mon Jan 19 14:50:54 EST 2015 +;; XFR size: 6 records (messages 1, bytes 234) + diff --git a/bin/tests/system/case/postupdate.good b/bin/tests/system/case/postupdate.good new file mode 100644 index 0000000000..66e5e36ed1 --- /dev/null +++ b/bin/tests/system/case/postupdate.good @@ -0,0 +1,6 @@ +dYNAMIc. 300 IN SOA mname1. . 2000042408 20 20 1814400 3600 +DyNaMiC. 300 IN NS ns1.DYNAMIC. +DyNaMiC. 300 IN MX 0 mail.eXaMpLe. +mAiL.DynamiC. 300 IN A 10.53.0.1 +ns1.DYNAMIC. 300 IN A 10.53.0.1 +dYNAMIc. 300 IN SOA mname1. . 2000042408 20 20 1814400 3600 diff --git a/bin/tests/system/case/setup.sh b/bin/tests/system/case/setup.sh new file mode 100644 index 0000000000..943a36d01e --- /dev/null +++ b/bin/tests/system/case/setup.sh @@ -0,0 +1,2 @@ +sh clean.sh +cp ns1/dynamic.db.in ns1/dynamic.db diff --git a/bin/tests/system/case/tests.sh b/bin/tests/system/case/tests.sh index 2c08d16878..46371edc3b 100644 --- a/bin/tests/system/case/tests.sh +++ b/bin/tests/system/case/tests.sh @@ -29,6 +29,13 @@ for i in 1 2 3 4 5 6 7 8 9 do $DIG $DIGOPTS soa example. @10.53.0.2 -p 5300 > dig.ns2.test$n grep SOA dig.ns2.test$n > /dev/null && break + sleep 1 +done +for i in 1 2 3 4 5 6 7 8 9 +do + $DIG $DIGOPTS soa dynamic. @10.53.0.2 -p 5300 > dig.ns2.test$n + grep SOA dig.ns2.test$n > /dev/null && break + sleep 1 done n=`expr $n + 1` @@ -57,5 +64,78 @@ grep "mail.example" dig.ns2.test$n > /dev/null || ret=1 test $ret -eq 0 || echo "I:failed" status=`expr $status + $ret` +n=`expr $n + 1` +echo "I:testing load of dynamic zone with various \$ORIGIN values ($n)" +ret=0 +$DIG axfr dynamic @10.53.0.1 -p 5300 > dig.ns1.test$n +$PERL ../digcomp.pl dig.ns1.test$n dynamic.good || ret=1 + +test $ret -eq 0 || echo "I:failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:transfer of dynamic zone with various \$ORIGIN values ($n)" +ret=0 +$DIG axfr dynamic @10.53.0.2 -p 5300 > dig.ns2.test$n +$PERL ../digcomp.pl dig.ns2.test$n dynamic.good || ret=1 + +test $ret -eq 0 || echo "I:failed" +status=`expr $status + $ret` + +n=`expr $n + 1` +echo "I:change SOA owner case via update ($n)" +$NSUPDATE << EOF +server 10.53.0.1 5300 +zone dynamic +update add dYNAMIc 0 SOA mname1. . 2000042408 20 20 1814400 3600 +send +EOF +$DIG axfr dynamic @10.53.0.1 -p 5300 > dig.ns1.test$n +$PERL ../digcomp.pl dig.ns1.test$n postupdate.good || ret=1 + +test $ret -eq 0 || echo "I:failed" +status=`expr $status + $ret` + +for i in 1 2 3 4 5 6 7 8 9 +do + $DIG soa dynamic @10.53.0.2 -p 5300 | grep 2000042408 > /dev/null && break + sleep 1 +done + +n=`expr $n + 1` +echo "I:check SOA owner case is transfered to slave ($n)" +ret=0 +$DIG axfr dynamic @10.53.0.2 -p 5300 > dig.ns2.test$n +$PERL ../digcomp.pl dig.ns2.test$n postupdate.good || ret=1 + +test $ret -eq 0 || echo "I:failed" +status=`expr $status + $ret` + +#update delete Ns1.DyNaMIC. 300 IN A 10.53.0.1 +n=`expr $n + 1` +echo "I:change A record owner case via update ($n)" +$NSUPDATE << EOF +server 10.53.0.1 5300 +zone dynamic +update add Ns1.DyNaMIC. 300 IN A 10.53.0.1 +send +EOF +$DIG axfr dynamic @10.53.0.1 -p 5300 > dig.ns1.test$n +$PERL ../digcomp.pl dig.ns1.test$n postns1.good || ret=1 + +test $ret -eq 0 || echo "I:failed" +status=`expr $status + $ret` + +for i in 1 2 3 4 5 6 7 8 9 +do + $DIG soa dynamic @10.53.0.2 -p 5300 | grep 2000042409 > /dev/null && break + sleep 1 +done + +n=`expr $n + 1` +echo "I:check A owner case is transfered to slave ($n)" +ret=0 +$DIG axfr dynamic @10.53.0.2 -p 5300 > dig.ns2.test$n +$PERL ../digcomp.pl dig.ns2.test$n postns1.good || ret=1 echo "I:exit status: $status" exit $status diff --git a/lib/dns/compress.c b/lib/dns/compress.c index 11473ee95f..ca81b925fa 100644 --- a/lib/dns/compress.c +++ b/lib/dns/compress.c @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: compress.c,v 1.59 2007/06/19 23:47:16 tbox Exp $ */ - /*! \file */ #define DNS_NAME_USEINLINE 1 @@ -71,6 +69,9 @@ dns_compress_invalidate(dns_compress_t *cctx) { while (cctx->table[i] != NULL) { node = cctx->table[i]; cctx->table[i] = cctx->table[i]->next; + if ((node->offset & 0x8000) != 0) + isc_mem_put(cctx->mctx, node->r.base, + node->r.length); if (node->count < DNS_COMPRESS_INITIALNODES) continue; isc_mem_put(cctx->mctx, node, sizeof(*node)); @@ -181,7 +182,7 @@ dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name, else dns_name_getlabelsequence(name, 0, n, prefix); - *offset = node->offset; + *offset = (node->offset & 0x7fff); return (ISC_TRUE); } @@ -196,7 +197,7 @@ void dns_compress_add(dns_compress_t *cctx, const dns_name_t *name, const dns_name_t *prefix, isc_uint16_t offset) { - dns_name_t tname; + dns_name_t tname, xname; unsigned int start; unsigned int n; unsigned int count; @@ -205,22 +206,37 @@ dns_compress_add(dns_compress_t *cctx, const dns_name_t *name, unsigned int length; unsigned int tlength; isc_uint16_t toffset; + unsigned char *tmp; + isc_region_t r; REQUIRE(VALID_CCTX(cctx)); REQUIRE(dns_name_isabsolute(name)); + if (offset > 0x4000) + return; dns_name_init(&tname, NULL); + dns_name_init(&xname, NULL); n = dns_name_countlabels(name); count = dns_name_countlabels(prefix); if (dns_name_isabsolute(prefix)) count--; + if (count == 0) + return; start = 0; - length = name_length(name); + dns_name_toregion(name, &r); + length = r.length; + tmp = isc_mem_get(cctx->mctx, length); + if (tmp == NULL) + return; + memmove(tmp, r.base, r.length); + r.base = tmp; + dns_name_fromregion(&xname, &r); + while (count > 0) { if (offset >= 0x4000) break; - dns_name_getlabelsequence(name, start, n, &tname); + dns_name_getlabelsequence(&xname, start, n, &tname); hash = dns_name_hash(&tname, ISC_FALSE) % DNS_COMPRESS_TABLESIZE; tlength = name_length(&tname); @@ -233,10 +249,16 @@ dns_compress_add(dns_compress_t *cctx, const dns_name_t *name, else { node = isc_mem_get(cctx->mctx, sizeof(dns_compressnode_t)); - if (node == NULL) + if (node == NULL) { + if (start == 0) + isc_mem_put(cctx->mctx, + r.base, r.length); return; + } } node->count = cctx->count++; + if (start == 0) + toffset |= 0x8000; node->offset = toffset; dns_name_toregion(&tname, &node->r); node->labels = (isc_uint8_t)dns_name_countlabels(&tname); @@ -263,8 +285,11 @@ dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset) { * items with the greatest offsets being at the end * of the initialnodes[] array. */ - while (node != NULL && node->offset >= offset) { + while (node != NULL && (node->offset & 0x7fff) >= offset) { cctx->table[i] = node->next; + if ((node->offset & 0x8000) != 0) + isc_mem_put(cctx->mctx, node->r.base, + node->r.length); if (node->count >= DNS_COMPRESS_INITIALNODES) isc_mem_put(cctx->mctx, node, sizeof(*node)); cctx->count--; diff --git a/lib/dns/diff.c b/lib/dns/diff.c index 4a711a5b33..39ad559f60 100644 --- a/lib/dns/diff.c +++ b/lib/dns/diff.c @@ -175,7 +175,7 @@ dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep) ot = next_ot) { next_ot = ISC_LIST_NEXT(ot, link); - if (dns_name_equal(&ot->name, &(*tuplep)->name) && + if (dns_name_caseequal(&ot->name, &(*tuplep)->name) && dns_rdata_compare(&ot->rdata, &(*tuplep)->rdata) == 0 && ot->ttl == (*tuplep)->ttl) { @@ -233,6 +233,18 @@ setresign(dns_rdataset_t *modified) { return (when); } +static void +getownercase(dns_rdataset_t *rdataset, dns_name_t *name) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_getownercase(rdataset, name); +} + +static void +setownercase(dns_rdataset_t *rdataset, dns_name_t *name) { + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_setownercase(rdataset, name); +} + static isc_result_t diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, isc_boolean_t warn) @@ -268,7 +280,7 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, dns_rdatalist_t rdl; dns_rdataset_t rds; dns_rdataset_t ardataset; - dns_rdataset_t *modified = NULL; + unsigned int options; op = t->op; type = t->rdata.type; @@ -311,13 +323,20 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, t->rdata.type == type && rdata_covers(&t->rdata) == covers) { - dns_name_format(name, namebuf, sizeof(namebuf)); - dns_rdatatype_format(t->rdata.type, typebuf, - sizeof(typebuf)); - dns_rdataclass_format(t->rdata.rdclass, - classbuf, - sizeof(classbuf)); - if (t->ttl != rdl.ttl && warn) + /* + * Remember the add name for + * dns_rdataset_setownercase. + */ + name = &t->name; + if (t->ttl != rdl.ttl && warn) { + dns_name_format(name, namebuf, + sizeof(namebuf)); + dns_rdatatype_format(t->rdata.type, + typebuf, + sizeof(typebuf)); + dns_rdataclass_format(t->rdata.rdclass, + classbuf, + sizeof(classbuf)); isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_WARNING, "'%s/%s/%s': TTL differs in " @@ -326,6 +345,7 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, namebuf, typebuf, classbuf, (unsigned long) t->ttl, (unsigned long) rdl.ttl); + } ISC_LIST_APPEND(rdl.rdata, &t->rdata, link); t = ISC_LIST_NEXT(t, link); } @@ -334,17 +354,8 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, * Convert the rdatalist into a rdataset. */ dns_rdataset_init(&rds); + dns_rdataset_init(&ardataset); CHECK(dns_rdatalist_tordataset(&rdl, &rds)); - if (rds.type == dns_rdatatype_rrsig) - switch (op) { - case DNS_DIFFOP_ADDRESIGN: - case DNS_DIFFOP_DELRESIGN: - modified = &ardataset; - dns_rdataset_init(modified); - break; - default: - break; - } rds.trust = dns_trust_ultimate; /* @@ -353,31 +364,38 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, switch (op) { case DNS_DIFFOP_ADD: case DNS_DIFFOP_ADDRESIGN: + options = DNS_DBADD_MERGE | DNS_DBADD_EXACT | + DNS_DBADD_EXACTTTL; result = dns_db_addrdataset(db, node, ver, - 0, &rds, - DNS_DBADD_MERGE| - DNS_DBADD_EXACT| - DNS_DBADD_EXACTTTL, - modified); + 0, &rds, options, + &ardataset); break; case DNS_DIFFOP_DEL: case DNS_DIFFOP_DELRESIGN: + options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD; result = dns_db_subtractrdataset(db, node, ver, - &rds, - DNS_DBSUB_EXACT, - modified); + &rds, options, + &ardataset); break; default: INSIST(0); } if (result == ISC_R_SUCCESS) { - if (modified != NULL) { + if (rds.type == dns_rdatatype_rrsig && + (op == DNS_DIFFOP_DELRESIGN || + op == DNS_DIFFOP_ADDRESIGN)) { isc_stdtime_t resign; - resign = setresign(modified); - dns_db_setsigningtime(db, modified, + resign = setresign(&ardataset); + dns_db_setsigningtime(db, &ardataset, resign); } + if (op == DNS_DIFFOP_ADD || + op == DNS_DIFFOP_ADDRESIGN) + setownercase(&ardataset, name); + if (op == DNS_DIFFOP_DEL || + op == DNS_DIFFOP_DELRESIGN) + getownercase(&ardataset, name); } else if (result == DNS_R_UNCHANGED) { /* * This will not happen when executing a @@ -400,20 +418,29 @@ diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver, "update with no effect", namebuf, classbuf); } + if (op == DNS_DIFFOP_ADD || + op == DNS_DIFFOP_ADDRESIGN) + setownercase(&ardataset, name); + if (op == DNS_DIFFOP_DEL || + op == DNS_DIFFOP_DELRESIGN) + getownercase(&ardataset, name); } else if (result == DNS_R_NXRRSET) { /* * OK. */ + if (op == DNS_DIFFOP_DEL || + op == DNS_DIFFOP_DELRESIGN) + getownercase(&ardataset, name); + if (dns_rdataset_isassociated(&ardataset)) + dns_rdataset_disassociate(&ardataset); } else { - if (modified != NULL && - dns_rdataset_isassociated(modified)) - dns_rdataset_disassociate(modified); + if (dns_rdataset_isassociated(&ardataset)) + dns_rdataset_disassociate(&ardataset); CHECK(result); } dns_db_detachnode(db, &node); - if (modified != NULL && - dns_rdataset_isassociated(modified)) - dns_rdataset_disassociate(modified); + if (dns_rdataset_isassociated(&ardataset)) + dns_rdataset_disassociate(&ardataset); } } return (ISC_R_SUCCESS); diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c index 553a339bb5..1adcba39c5 100644 --- a/lib/dns/ecdb.c +++ b/lib/dns/ecdb.c @@ -114,7 +114,9 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, /* putadditional */ rdataset_settrust, /* settrust */ NULL, /* expire */ - NULL /* clearprefetch */ + NULL, /* clearprefetch */ + NULL, /* setownercase */ + NULL /* getownercase */ }; typedef struct ecdb_rdatasetiter { diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 2519796b35..d203d3d09f 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -260,6 +260,7 @@ struct dns_db { * Options that can be specified for dns_db_subtractrdataset(). */ #define DNS_DBSUB_EXACT 0x01 +#define DNS_DBSUB_WANTOLD 0x02 /*@{*/ /*% @@ -1281,6 +1282,9 @@ dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, * become nonexistent. If DNS_DBSUB_EXACT is set then all elements * of 'rdataset' must exist at 'node'. * + *\li If DNS_DBSUB_WANTOLD is set and the entire rdataset was deleted + * then return the original rdatatset in newrdataset if that existed. + * * Requires: * * \li 'db' is a valid database. diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index b3dd2d86e1..e8ac6c9c39 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -811,14 +811,15 @@ dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, #define DNS_NAME_MASTERFILE 0x02U /* escape $ and @ */ isc_result_t -dns_name_toprincipal(dns_name_t *name, isc_buffer_t *target); +dns_name_toprincipal(const dns_name_t *name, isc_buffer_t *target); isc_result_t -dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot, +dns_name_totext(const dns_name_t *name, isc_boolean_t omit_final_dot, isc_buffer_t *target); isc_result_t -dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target); +dns_name_totext2(const dns_name_t *name, unsigned int options, + isc_buffer_t *target); /*%< * Convert 'name' into text format, storing the result in 'target'. * @@ -1125,7 +1126,7 @@ dns_name_print(dns_name_t *name, FILE *stream); */ void -dns_name_format(dns_name_t *name, char *cp, unsigned int size); +dns_name_format(const dns_name_t *name, char *cp, unsigned int size); /*%< * Format 'name' as text appropriate for use in log messages. * @@ -1222,7 +1223,7 @@ dns_name_settotextfilter(dns_name_totextfilter_t proc); */ isc_result_t -dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target); +dns_name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target); /*%< * Makes 'dest' refer to a copy of the name in 'source'. The data are * either copied to 'target' or the dedicated buffer in 'dest'. diff --git a/lib/dns/include/dns/rdatalist.h b/lib/dns/include/dns/rdatalist.h index 57debc3951..dc7a0a0de6 100644 --- a/lib/dns/include/dns/rdatalist.h +++ b/lib/dns/include/dns/rdatalist.h @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdatalist.h,v 1.22 2008/04/03 06:09:05 tbox Exp $ */ - #ifndef DNS_RDATALIST_H #define DNS_RDATALIST_H 1 @@ -58,6 +56,12 @@ struct dns_rdatalist { dns_ttl_t ttl; ISC_LIST(dns_rdata_t) rdata; ISC_LINK(dns_rdatalist_t) link; + /*%< + * Case vector. If the bit is set then the corresponding + * character in the owner name needs to be AND'd with 0x20, + * rendering that character upper case. + */ + unsigned char upper[32]; }; ISC_LANG_BEGINDECLS diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 252738d075..5c32958523 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -15,8 +15,6 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rdataset.h,v 1.72 2011/06/08 22:13:51 each Exp $ */ - #ifndef DNS_RDATASET_H #define DNS_RDATASET_H 1 @@ -115,6 +113,9 @@ typedef struct dns_rdatasetmethods { dns_trust_t trust); void (*expire)(dns_rdataset_t *rdataset); void (*clearprefetch)(dns_rdataset_t *rdataset); + void (*setownercase)(dns_rdataset_t *rdataset, + const dns_name_t *name); + void (*getownercase)(const dns_rdataset_t *rdataset, dns_name_t *name); } dns_rdatasetmethods_t; #define DNS_RDATASET_MAGIC ISC_MAGIC('D','N','S','R') @@ -666,6 +667,22 @@ dns_rdataset_clearprefetch(dns_rdataset_t *rdataset); * It has no function in other databases. */ +void +dns_rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name); +/*%< + * Store the casing of 'name', the owner name of 'rdataset', into + * a bitfield so that the name can be capitalized the same when when + * the rdataset is used later. This sets the CASESET attribute. + */ + +void +dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); +/*%< + * If the CASESET attribute is set, retrieve the case bitfield that was + * previously stored by dns_rdataset_getownername(), and capitalize 'name' + * according to it. If CASESET is not set, do nothing. + */ + void dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_rdata_rrsig_t *rrsig, isc_stdtime_t now, diff --git a/lib/dns/journal.c b/lib/dns/journal.c index 4356709466..dadc804829 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -139,9 +139,12 @@ dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, dns_dbnode_t *node; dns_rdataset_t rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; + dns_fixedname_t fixed; dns_name_t *zonename; - zonename = dns_db_origin(db); + dns_fixedname_init(&fixed); + zonename = dns_fixedname_name(&fixed); + dns_name_copy(dns_db_origin(db), zonename, NULL); node = NULL; result = dns_db_findnode(db, zonename, ISC_FALSE, &node); @@ -159,6 +162,7 @@ dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, goto freenode; dns_rdataset_current(&rdataset, &rdata); + dns_rdataset_getownercase(&rdataset, zonename); result = dns_difftuple_create(mctx, op, zonename, rdataset.ttl, &rdata, tp); diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 92f7a2cae2..31a7db59aa 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -449,6 +449,8 @@ rdataset_totext(dns_rdataset_t *rdataset, isc_boolean_t current_ttl_valid; dns_rdatatype_t type; unsigned int type_start; + dns_fixedname_t fixed; + dns_name_t *name = NULL; REQUIRE(DNS_RDATASET_VALID(rdataset)); @@ -458,6 +460,13 @@ rdataset_totext(dns_rdataset_t *rdataset, current_ttl = ctx->current_ttl; current_ttl_valid = ctx->current_ttl_valid; + if (owner_name != NULL) { + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_name_copy(owner_name, name, NULL); + dns_rdataset_getownercase(rdataset, name); + } + while (result == ISC_R_SUCCESS) { column = 0; @@ -470,14 +479,12 @@ rdataset_totext(dns_rdataset_t *rdataset, /* * Owner name. */ - if (owner_name != NULL && + if (name != NULL && ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 && !first)) { unsigned int name_start = target->used; - RETERR(dns_name_totext(owner_name, - omit_final_dot, - target)); + RETERR(dns_name_totext(name, omit_final_dot, target)); column += target->used - name_start; } diff --git a/lib/dns/message.c b/lib/dns/message.c index c4fa468556..095028abef 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -336,6 +336,7 @@ newrdatalist(dns_message_t *msg) { rdatalist = ISC_LIST_HEAD(msg->freerdatalist); if (rdatalist != NULL) { ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link); + dns_rdatalist_init(rdatalist); return (rdatalist); } @@ -352,6 +353,8 @@ newrdatalist(dns_message_t *msg) { rdatalist = msgblock_get(msgblock, dns_rdatalist_t); } + if (rdatalist != NULL) + dns_rdatalist_init(rdatalist); return (rdatalist); } @@ -1127,10 +1130,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, * the name. */ rdatalist->type = rdtype; - rdatalist->covers = 0; rdatalist->rdclass = rdclass; - rdatalist->ttl = 0; - ISC_LIST_INIT(rdatalist->rdata); dns_rdataset_init(rdataset); result = dns_rdatalist_tordataset(rdatalist, rdataset); @@ -1491,12 +1491,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, rdatalist->covers = covers; rdatalist->rdclass = rdclass; rdatalist->ttl = ttl; - ISC_LIST_INIT(rdatalist->rdata); dns_rdataset_init(rdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS); + dns_rdataset_setownercase(rdataset, name); if (rdtype != dns_rdatatype_opt && rdtype != dns_rdatatype_tsig && diff --git a/lib/dns/name.c b/lib/dns/name.c index 9b2c6b3d98..7fd16be3f5 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -1368,7 +1368,7 @@ totext_filter_proc_key_init(void) { #endif isc_result_t -dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot, +dns_name_totext(const dns_name_t *name, isc_boolean_t omit_final_dot, isc_buffer_t *target) { unsigned int options = DNS_NAME_MASTERFILE; @@ -1379,12 +1379,13 @@ dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot, } isc_result_t -dns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) { +dns_name_toprincipal(const dns_name_t *name, isc_buffer_t *target) { return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target)); } isc_result_t -dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target) +dns_name_totext2(const dns_name_t *name, unsigned int options, + isc_buffer_t *target) { unsigned char *ndata; char *tdata; @@ -2383,7 +2384,7 @@ dns_name_settotextfilter(dns_name_totextfilter_t proc) { } void -dns_name_format(dns_name_t *name, char *cp, unsigned int size) { +dns_name_format(const dns_name_t *name, char *cp, unsigned int size) { isc_result_t result; isc_buffer_t buf; @@ -2476,7 +2477,7 @@ dns_name_fromstring2(dns_name_t *target, const char *src, } isc_result_t -dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { +dns_name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) { unsigned char *ndata; /* diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c index f122107e2f..96a863175f 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -504,6 +504,8 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, rdataset_settrust, NULL, + NULL, + NULL, NULL }; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index ce39729804..859f4f6d0a 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -149,6 +149,7 @@ typedef isc_uint64_t rbtdb_serial_t; #define dbiterator_methods dbiterator_methods64 #define rdataset_methods rdataset_methods64 #define rdatasetiter_methods rdatasetiter_methods64 +#define slab_methods slab_methods64 #define zone_methods zone_methods64 #define acache_callback acache_callback64 @@ -451,6 +452,12 @@ typedef struct rdatasetheader { * Used for TTL-based cache cleaning. */ isc_stdtime_t resign; + /*%< + * Case vector. If the bit is set then the corresponding + * character in the owner name needs to be AND'd with 0x20, + * rendering that character upper case. + */ + unsigned char upper[32]; } rdatasetheader_t; typedef ISC_LIST(rdatasetheader_t) rdatasetheaderlist_t; @@ -466,6 +473,7 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t; #define RDATASET_ATTR_OPTOUT 0x0080 #define RDATASET_ATTR_NEGATIVE 0x0100 #define RDATASET_ATTR_PREFETCH 0x0200 +#define RDATASET_ATTR_CASESET 0x0400 typedef struct acache_cbarg { dns_rdatasetadditional_t type; @@ -508,6 +516,8 @@ struct acachectl { (((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0) #define PREFETCH(header) \ (((header)->attributes & RDATASET_ATTR_PREFETCH) != 0) +#define CASESET(header) \ + (((header)->attributes & RDATASET_ATTR_CASESET) != 0) #define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ @@ -746,6 +756,10 @@ static void prune_tree(isc_task_t *task, isc_event_t *event); static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); static void rdataset_expire(dns_rdataset_t *rdataset); static void rdataset_clearprefetch(dns_rdataset_t *rdataset); +static void rdataset_setownercase(dns_rdataset_t *rdataset, + const dns_name_t *name); +static void rdataset_getownercase(const dns_rdataset_t *rdataset, + dns_name_t *name); static dns_rdatasetmethods_t rdataset_methods = { rdataset_disassociate, @@ -763,7 +777,30 @@ static dns_rdatasetmethods_t rdataset_methods = { rdataset_putadditional, rdataset_settrust, rdataset_expire, - rdataset_clearprefetch + rdataset_clearprefetch, + rdataset_setownercase, + rdataset_getownercase +}; + +static dns_rdatasetmethods_t slab_methods = { + rdataset_disassociate, + rdataset_first, + rdataset_next, + rdataset_current, + rdataset_clone, + rdataset_count, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL }; static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp); @@ -841,6 +878,7 @@ static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event); static void overmem(dns_db_t *db, isc_boolean_t over); static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version); +static void setownercase(rdatasetheader_t *header, const dns_name_t *name); /* Pad to 32 bytes */ static char FILE_VERSION[32] = "\0"; @@ -1543,6 +1581,10 @@ update_newheader(rdatasetheader_t *new, rdatasetheader_t *old) { p += (uintptr_t)old->node; new->node = (dns_rbtnode_t *)p; } + if (CASESET(old)) { + memmove(new->upper, old->upper, sizeof(old->upper)); + new->attributes |= RDATASET_ATTR_CASESET; + } } static inline rdatasetheader_t * @@ -1557,6 +1599,7 @@ new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx) { if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) fprintf(stderr, "allocated header: %p\n", h); #endif + memset(h->upper, 0xeb, sizeof(h->upper)); init_rdataset(rbtdb, h); return (h); } @@ -6619,6 +6662,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_boolean_t newnsec; isc_boolean_t tree_locked = ISC_FALSE; isc_boolean_t cache_is_overmem = ISC_FALSE; + dns_fixedname_t fixed; + dns_name_t *name; REQUIRE(VALID_RBTDB(rbtdb)); INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb); @@ -6642,8 +6687,14 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, if (result != ISC_R_SUCCESS) return (result); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_rbt_fullnamefromnode(node, name); + dns_rdataset_getownercase(rdataset, name); + newheader = (rdatasetheader_t *)region.base; init_rdataset(rbtdb, newheader); + setownercase(newheader, name); set_ttl(rbtdb, newheader, rdataset->ttl + now); newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type, rdataset->covers); @@ -6825,8 +6876,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rdataset->covers != dns_rdatatype_nsec3))); result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, - ®ion, - sizeof(rdatasetheader_t)); + ®ion, sizeof(rdatasetheader_t)); if (result != ISC_R_SUCCESS) return (result); newheader = (rdatasetheader_t *)region.base; @@ -6973,6 +7023,10 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, if (result == ISC_R_SUCCESS && newrdataset != NULL) bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset); + if (result == DNS_R_NXRRSET && newrdataset != NULL && + (options & DNS_DBSUB_WANTOLD) != 0) + bind_rdataset(rbtdb, rbtnode, header, 0, newrdataset); + unlock: NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); @@ -7240,6 +7294,8 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { newheader->additional_glue = NULL; newheader->last_used = 0; newheader->node = node; + setownercase(newheader, name); + if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { newheader->attributes |= RDATASET_ATTR_RESIGN; newheader->resign = rdataset->resign; @@ -8615,7 +8671,7 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, cloned_node = NULL; attachnode(db, node, &cloned_node); - nsec->methods = &rdataset_methods; + nsec->methods = &slab_methods; nsec->rdclass = db->rdclass; nsec->type = noqname->type; nsec->covers = 0; @@ -8631,7 +8687,7 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, cloned_node = NULL; attachnode(db, node, &cloned_node); - nsecsig->methods = &rdataset_methods; + nsecsig->methods = &slab_methods; nsecsig->rdclass = db->rdclass; nsecsig->type = dns_rdatatype_rrsig; nsecsig->covers = noqname->type; @@ -8661,7 +8717,7 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, cloned_node = NULL; attachnode(db, node, &cloned_node); - nsec->methods = &rdataset_methods; + nsec->methods = &slab_methods; nsec->rdclass = db->rdclass; nsec->type = closest->type; nsec->covers = 0; @@ -8677,7 +8733,7 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, cloned_node = NULL; attachnode(db, node, &cloned_node); - nsecsig->methods = &rdataset_methods; + nsecsig->methods = &slab_methods; nsecsig->rdclass = db->rdclass; nsecsig->type = dns_rdatatype_rrsig; nsecsig->covers = closest->type; @@ -9774,6 +9830,54 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, return (ISC_R_SUCCESS); } +static void +setownercase(rdatasetheader_t *header, const dns_name_t *name) { + unsigned int i; + + /* + * We do not need to worry about label lengths as they are all + * less than or equal to 63. + */ + memset(header->upper, 0, sizeof(header->upper)); + for (i = 0; i < name->length; i++) + if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) + header->upper[i/8] |= 1 << (i%8); + header->attributes |= RDATASET_ATTR_CASESET; +} + +static void +rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { + unsigned char *raw = rdataset->private3; /* RDATASLAB */ + rdatasetheader_t *header; + + header = (struct rdatasetheader *)(raw - sizeof(*header)); + setownercase(header, name); +} + +static void +rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { + const unsigned char *raw = rdataset->private3; /* RDATASLAB */ + const rdatasetheader_t *header; + unsigned int i; + + header = (const struct rdatasetheader *)(raw - sizeof(*header)); + + if (!CASESET(header)) + return; + + for (i = 0; i < name->length; i++) { + /* + * Set the case bit if it does not match the recorded bit. + */ + if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a && + (header->upper[i/8] & (1 << (i%8))) != 0) + name->ndata[i] &= ~0x20; /* clear the lower case bit */ + else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a && + (header->upper[i/8] & (1 << (i%8))) == 0) + name->ndata[i] |= 0x20; /* set the lower case bit */ + } +} + /*% * Routines for LRU-based cache management. */ diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c index d9eca82c18..9a4d31da5b 100644 --- a/lib/dns/rdatalist.c +++ b/lib/dns/rdatalist.c @@ -22,6 +22,7 @@ #include #include +#include #include @@ -49,7 +50,9 @@ static dns_rdatasetmethods_t methods = { NULL, NULL, NULL, - NULL + NULL, + isc__rdatalist_setownercase, + isc__rdatalist_getownercase }; void @@ -67,6 +70,11 @@ dns_rdatalist_init(dns_rdatalist_t *rdatalist) { rdatalist->ttl = 0; ISC_LIST_INIT(rdatalist->rdata); ISC_LINK_INIT(rdatalist, link); + memset(rdatalist->upper, 0xeb, sizeof(rdatalist->upper)); + /* + * Clear upper set bit. + */ + rdatalist->upper[0] &= ~0x01; } isc_result_t @@ -368,3 +376,44 @@ isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_clone(tnegsig, negsig); return (ISC_R_SUCCESS); } + +void +isc__rdatalist_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { + dns_rdatalist_t *rdatalist; + unsigned int i; + + /* + * We do not need to worry about label lengths as they are all + * less than or equal to 63. + */ + rdatalist = rdataset->private1; + memset(rdatalist->upper, 0, sizeof(rdatalist->upper)); + for (i = 1; i < name->length; i++) + if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) + rdatalist->upper[i/8] |= 1 << (i%8); + /* + * Record that upper has been set. + */ + rdatalist->upper[0] |= 0x01; +} + +void +isc__rdatalist_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { + dns_rdatalist_t *rdatalist; + unsigned int i; + + rdatalist = rdataset->private1; + if ((rdatalist->upper[0] & 0x01) == 0) + return; + for (i = 0; i < name->length; i++) { + /* + * Set the case bit if it does not match the recorded bit. + */ + if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a && + (rdatalist->upper[i/8] & (1 << (i%8))) != 0) + name->ndata[i] &= ~0x20; /* clear the lower case bit */ + else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a && + (rdatalist->upper[i/8] & (1 << (i%8))) == 0) + name->ndata[i] |= 0x20; /* set the lower case bit */ + } +} diff --git a/lib/dns/rdatalist_p.h b/lib/dns/rdatalist_p.h index 3e73e20aa5..653f8dd9ff 100644 --- a/lib/dns/rdatalist_p.h +++ b/lib/dns/rdatalist_p.h @@ -59,6 +59,12 @@ isc_result_t isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *neg, dns_rdataset_t *negsig); +void +isc__rdatalist_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name); + +void +isc__rdatalist_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); + ISC_LANG_ENDDECLS #endif /* DNS_RDATALIST_P_H */ diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index 1870394508..88d67860f6 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -29,11 +29,12 @@ #include #include +#include +#include #include #include #include #include -#include static const char *trustnames[] = { "none", @@ -207,6 +208,8 @@ static dns_rdatasetmethods_t question_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; @@ -329,6 +332,8 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, isc_boolean_t shuffle = ISC_FALSE; dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE]; struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE]; + dns_fixedname_t fixed; + dns_name_t *name; UNUSED(state); @@ -467,6 +472,11 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, i = 0; added = 0; + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_name_copy(owner_name, name, NULL); + dns_rdataset_getownercase(rdataset, name); + do { /* * Copy out the name, type, class, ttl. @@ -474,7 +484,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, rrbuffer = *target; dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); - result = dns_name_towire(owner_name, cctx, target); + result = dns_name_towire(name, cctx, target); if (result != ISC_R_SUCCESS) goto rollback; headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t); @@ -784,6 +794,24 @@ dns_rdataset_clearprefetch(dns_rdataset_t *rdataset) { (rdataset->methods->clearprefetch)(rdataset); } +void +dns_rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { + REQUIRE(DNS_RDATASET_VALID(rdataset)); + REQUIRE(rdataset->methods != NULL); + + if (rdataset->methods->setownercase != NULL) + (rdataset->methods->setownercase)(rdataset, name); +} + +void +dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { + REQUIRE(DNS_RDATASET_VALID(rdataset)); + REQUIRE(rdataset->methods != NULL); + + if (rdataset->methods->getownercase != NULL) + (rdataset->methods->getownercase)(rdataset, name); +} + void dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_rdata_rrsig_t *rrsig, isc_stdtime_t now, diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index e29dc8415a..6890550272 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -467,6 +467,8 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; diff --git a/lib/dns/rriterator.c b/lib/dns/rriterator.c index 509fb42270..c7924f12f0 100644 --- a/lib/dns/rriterator.c +++ b/lib/dns/rriterator.c @@ -100,6 +100,8 @@ dns_rriterator_first(dns_rriterator_t *it) { continue; } dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); + dns_rdataset_getownercase(&it->rdataset, + dns_fixedname_name(&it->fixedname)); it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; it->result = dns_rdataset_first(&it->rdataset); return (it->result); @@ -140,6 +142,8 @@ dns_rriterator_nextrrset(dns_rriterator_t *it) { if (it->result != ISC_R_SUCCESS) return (it->result); dns_rdatasetiter_current(it->rdatasetit, &it->rdataset); + dns_rdataset_getownercase(&it->rdataset, + dns_fixedname_name(&it->fixedname)); it->rdataset.attributes |= DNS_RDATASETATTR_LOADORDER; it->result = dns_rdataset_first(&it->rdataset); return (it->result); diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index b3a1e0f47b..2e767038e3 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -1430,6 +1430,8 @@ static dns_rdatasetmethods_t methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index dd4d08dc07..78dd819036 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -1482,6 +1482,8 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, NULL, NULL, + NULL, + NULL, NULL }; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index bd62c3847f..8367c50c7d 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -13763,6 +13763,8 @@ checkandaddsoa(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_buffer_t b; isc_result_t result; unsigned char buf[DNS_SOA_BUFFERSIZE]; + dns_fixedname_t fixed; + dns_name_t *name; result = dns_rdataset_first(rdataset); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -13799,6 +13801,11 @@ checkandaddsoa(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdataset_init(&temprdataset); result = dns_rdatalist_tordataset(&temprdatalist, &temprdataset); RUNTIME_CHECK(result == ISC_R_SUCCESS); + dns_fixedname_init(&fixed); + name = dns_fixedname_name(&fixed); + dns_rbtnode_nodename(node, name); + dns_rdataset_getownercase(rdataset, name); + dns_rdataset_setownercase(&temprdataset, name); return (dns_db_addrdataset(db, node, version, 0, &temprdataset, 0, NULL)); } diff --git a/lib/samples/sample-update.c b/lib/samples/sample-update.c index 5a8a9a0bb4..b98ff79096 100644 --- a/lib/samples/sample-update.c +++ b/lib/samples/sample-update.c @@ -587,7 +587,6 @@ update_addordelete(isc_mem_t *mctx, char *cmdline, isc_boolean_t isdelete, rdatalist->rdclass = rdataclass; rdatalist->covers = rdatatype; rdatalist->ttl = (dns_ttl_t)ttl; - ISC_LIST_INIT(rdatalist->rdata); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); ISC_LIST_APPEND(usedrdatalists, rdatalist, link); @@ -598,6 +597,7 @@ update_addordelete(isc_mem_t *mctx, char *cmdline, isc_boolean_t isdelete, } dns_rdataset_init(rdataset); dns_rdatalist_tordataset(rdatalist, rdataset); + dns_rdataset_setownercase(rdataset, name); ISC_LIST_INIT(name->list); ISC_LIST_APPEND(name->list, rdataset, link); } @@ -700,6 +700,7 @@ make_prereq(isc_mem_t *mctx, char *cmdline, isc_boolean_t ispositive, } dns_rdataset_init(rdataset); dns_rdatalist_tordataset(rdatalist, rdataset); + dns_rdataset_setownercase(rdataset, name); ISC_LIST_INIT(name->list); ISC_LIST_APPEND(name->list, rdataset, link); }