Commit a8da00ef authored by Mark Andrews's avatar Mark Andrews

4079. [func] Preserve the case of the ownername of records to

                        the RRset level. [RT #37442]
parent 414aa6bc
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]
......
......@@ -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);
......
......@@ -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;
/*
* 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 the update RR,
* 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;
......
......@@ -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
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
; 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
......@@ -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; };
};
......@@ -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; };
};
; <<>> 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)
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
sh clean.sh
cp ns1/dynamic.db.in ns1/dynamic.db
......@@ -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
......@@ -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--;
......
......@@ -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 ||