Compare commits

...
16 changed files with 626 additions and 78 deletions
+2
View File
@@ -170,6 +170,8 @@ prio_type(dns_typepair_t type) {
case DNS_SIGTYPE(dns_rdatatype_dname):
case dns_rdatatype_svcb:
case DNS_SIGTYPE(dns_rdatatype_svcb):
case dns_rdatatype_deleg:
case DNS_SIGTYPE(dns_rdatatype_deleg):
case dns_rdatatype_https:
case DNS_SIGTYPE(dns_rdatatype_https):
case dns_rdatatype_dnskey:
+2 -1
View File
@@ -422,7 +422,7 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
/*
* NS, SOA and DNSSKEY records are signed by their owner.
* DS records are signed by the parent.
* DS and DELEG records are signed by the parent.
*/
switch (set->type) {
case dns_rdatatype_ns:
@@ -434,6 +434,7 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
}
break;
case dns_rdatatype_ds:
case dns_rdatatype_deleg:
if (dns_name_equal(name, &sig.signer)) {
inc_stat(dns_dnssecstats_fail);
return (DNS_R_SIGINVALID);
+1 -1
View File
@@ -1895,7 +1895,7 @@ load_text(dns_loadctx_t *lctx) {
}
}
if (type == dns_rdatatype_svcb &&
if ((type == dns_rdatatype_svcb) &&
(lctx->options & DNS_MASTER_ZONE) != 0 &&
(lctx->options & DNS_MASTER_CHECKSVCB) != 0)
{
+6
View File
@@ -1202,6 +1202,9 @@ auth_signed(dns_namelist_t *section) {
case dns_rdatatype_nsec3:
auth_dnssec |= 0x4;
break;
case dns_rdatatype_deleg:
auth_dnssec |= 0x8;
break;
case dns_rdatatype_rrsig:
break;
default:
@@ -1218,6 +1221,9 @@ auth_signed(dns_namelist_t *section) {
case dns_rdatatype_nsec3:
auth_rrsig |= 0x4;
break;
case dns_rdatatype_deleg:
auth_rrsig |= 0x8;
break;
default:
break;
}
+9 -5
View File
@@ -144,13 +144,16 @@ dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
* 2) We set the RRSIG bit if we don't have
* a NS record but do have other data.
*/
if (rdataset.type == dns_rdatatype_soa ||
rdataset.type == dns_rdatatype_ds)
{
switch (rdataset.type) {
case dns_rdatatype_soa:
case dns_rdatatype_ds:
case dns_rdatatype_deleg:
need_rrsig = true;
} else if (rdataset.type == dns_rdatatype_ns) {
break;
case dns_rdatatype_ns:
found_ns = true;
} else {
break;
default:
found = true;
}
}
@@ -2106,6 +2109,7 @@ dns_nsec3_noexistnodata(dns_rdatatype_t type, const dns_name_t *name,
(dns_name_countlabels(closest) == 0 ||
dns_name_issubdomain(qname, closest)) &&
!dns_nsec3_typepresent(&rdata, dns_rdatatype_ds) &&
!dns_nsec3_typepresent(&rdata, dns_rdatatype_deleg) &&
!dns_nsec3_typepresent(&rdata,
dns_rdatatype_dname) &&
(dns_nsec3_typepresent(&rdata, dns_rdatatype_soa) ||
+30 -9
View File
@@ -1984,6 +1984,8 @@ findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
qpc_search_t search;
dns_slabheader_t *header = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabheader_t *found_ns = NULL, *found_nssig = NULL;
dns_slabheader_t *found_deleg = NULL, *found_delegsig = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
@@ -2072,21 +2074,30 @@ findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
* If we found a type we were looking for, remember
* it.
*/
if (header->type == dns_rdatatype_ns) {
switch (header->type) {
case dns_rdatatype_ns:
/*
* Remember a NS rdataset even if we're
* not specifically looking for it, because
* we might need it later.
*/
found = header;
} else if (header->type ==
DNS_SIGTYPE(dns_rdatatype_ns))
{
found_ns = header;
break;
case DNS_SIGTYPE(dns_rdatatype_ns):
/*
* If we need the NS rdataset, we'll also
* need its signature.
*/
foundsig = header;
found_nssig = header;
break;
case dns_rdatatype_deleg:
found_deleg = header;
break;
case DNS_SIGTYPE(dns_rdatatype_deleg):
found_delegsig = header;
break;
default:
break;
}
header_prev = header;
} else {
@@ -2094,9 +2105,9 @@ findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
}
}
if (found == NULL) {
if (found_deleg == NULL && found_ns == NULL) {
/*
* No NS records here.
* No NS nor DELEG records here.
*/
NODE_UNLOCK(lock, &nlocktype);
result = find_deepest_zonecut(&search, node, nodep, foundname,
@@ -2111,6 +2122,14 @@ findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
*nodep = node;
}
if (found_deleg) {
found = found_deleg;
foundsig = found_delegsig;
} else if (found_ns) {
found = found_ns;
foundsig = found_nssig;
}
bindrdataset(search.qpdb, node, found, search.now, nlocktype, tlocktype,
rdataset DNS__DB_FLARG_PASS);
if (foundsig != NULL) {
@@ -3107,7 +3126,9 @@ find_header:
(header->type == dns_rdatatype_a ||
header->type == dns_rdatatype_aaaa ||
header->type == dns_rdatatype_ds ||
header->type == DNS_SIGTYPE(dns_rdatatype_ds)) &&
header->type == DNS_SIGTYPE(dns_rdatatype_ds) ||
header->type == dns_rdatatype_deleg ||
header->type == DNS_SIGTYPE(dns_rdatatype_deleg)) &&
!header_nx && !newheader_nx &&
header->trust >= newheader->trust &&
dns_rdataslab_equal((unsigned char *)header,
+33 -13
View File
@@ -3153,6 +3153,7 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
dns_slabheader_t *header = NULL, *header_next = NULL;
dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
dns_slabheader_t *ns_header = NULL;
dns_slabheader_t *deleg_header = NULL, *sigdeleg_header = NULL;
dns_slabheader_t *found = NULL;
isc_result_t result = DNS_R_CONTINUE;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
@@ -3166,6 +3167,8 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
if (header->type == dns_rdatatype_ns ||
header->type == dns_rdatatype_deleg ||
header->type == DNS_SIGTYPE(dns_rdatatype_deleg) ||
header->type == dns_rdatatype_dname ||
header->type == DNS_SIGTYPE(dns_rdatatype_dname))
{
@@ -3181,22 +3184,35 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
header = header->down;
}
} while (header != NULL);
if (header != NULL) {
if (header->type == dns_rdatatype_dname) {
dname_header = header;
} else if (header->type ==
DNS_SIGTYPE(dns_rdatatype_dname))
{
sigdname_header = header;
} else if (node != search->qpdb->origin ||
IS_STUB(search->qpdb))
{
if (header == NULL) {
continue;
}
switch (header->type) {
case dns_rdatatype_dname:
dname_header = header;
break;
case DNS_SIGTYPE(dns_rdatatype_dname):
sigdname_header = header;
break;
case dns_rdatatype_deleg:
if (node != search->qpdb->origin) {
deleg_header = header;
}
break;
case DNS_SIGTYPE(dns_rdatatype_deleg):
sigdeleg_header = header;
break;
case dns_rdatatype_ns:
if (node != search->qpdb->origin || IS_STUB(search->qpdb)) {
/*
* We've found an NS rdataset that
* isn't at the origin node.
* We've found an NS rdataset that isn't at the origin node.
*/
ns_header = header;
}
break;
default:
break;
}
}
}
@@ -3204,7 +3220,11 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
/*
* Did we find anything?
*/
if (!IS_STUB(search->qpdb) && ns_header != NULL) {
if (deleg_header != NULL) {
/* DELEG has precedence over both NS and DNAME */
found = deleg_header;
search->zonecut_sigheader = sigdeleg_header;
} else if (!IS_STUB(search->qpdb) && ns_header != NULL) {
/*
* Note that NS has precedence over DNAME if both exist
* in a zone. Otherwise DNAME take precedence over NS.
+3 -1
View File
@@ -2884,7 +2884,9 @@ find_header:
(header->type == dns_rdatatype_a ||
header->type == dns_rdatatype_aaaa ||
header->type == dns_rdatatype_ds ||
header->type == DNS_SIGTYPE(dns_rdatatype_ds)) &&
header->type == DNS_SIGTYPE(dns_rdatatype_ds) ||
header->type == dns_rdatatype_deleg ||
header->type == DNS_SIGTYPE(dns_rdatatype_deleg)) &&
!header_nx && !newheader_nx &&
header->trust >= newheader->trust &&
dns_rdataslab_equal((unsigned char *)header,
+4 -4
View File
@@ -88,7 +88,7 @@
#define ARGS_FROMTEXT \
int rdclass, dns_rdatatype_t type, isc_lex_t *lexer, \
const dns_name_t *origin, unsigned int options, \
isc_buffer_t *target, dns_rdatacallbacks_t *callbacks
isc_buffer_t *target, dns_rdatacallbacks_t *callbacks ISC_ATTR_UNUSED
#define CALL_FROMTEXT rdclass, type, lexer, origin, options, target, callbacks
@@ -136,8 +136,8 @@
#define CALL_DIGEST rdata, digest, arg
#define ARGS_CHECKOWNER \
const dns_name_t *name, dns_rdataclass_t rdclass, \
dns_rdatatype_t type, bool wildcard
const dns_name_t *name ISC_ATTR_UNUSED, dns_rdataclass_t rdclass, \
dns_rdatatype_t type, bool wildcard ISC_ATTR_UNUSED
#define CALL_CHECKOWNER name, rdclass, type, wildcard
@@ -2448,7 +2448,7 @@ dns_rdata_checksvcb(const dns_name_t *owner, const dns_rdata_t *rdata) {
REQUIRE(owner != NULL);
REQUIRE(rdata != NULL);
REQUIRE(rdata->type == dns_rdatatype_svcb);
REQUIRE(rdata->type == dns_rdatatype_svcb || rdata->type == dns_rdatatype_deleg);
REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
result = dns_rdata_tostruct(rdata, &svcb, NULL);
+177
View File
@@ -0,0 +1,177 @@
/*
* 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.
*/
/* draft-wesplaap-deleg-01 */
#pragma once
#include <stdbool.h>
#include <isc/result.h>
#define RRTYPE_DELEG_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL)
static isc_result_t
fromtext_in_deleg(ARGS_FROMTEXT) {
REQUIRE(type == dns_rdatatype_deleg);
REQUIRE(rdclass == dns_rdataclass_in);
return (generic_fromtext_in_svcb(CALL_FROMTEXT));
}
static isc_result_t
totext_in_deleg(ARGS_TOTEXT) {
REQUIRE(rdata->type == dns_rdatatype_deleg);
REQUIRE(rdata->rdclass == dns_rdataclass_in);
REQUIRE(rdata->length != 0);
return (generic_totext_in_svcb(CALL_TOTEXT));
}
static isc_result_t
fromwire_in_deleg(ARGS_FROMWIRE) {
REQUIRE(type == dns_rdatatype_deleg);
REQUIRE(rdclass == dns_rdataclass_in);
return (generic_fromwire_in_svcb(CALL_FROMWIRE));
}
static isc_result_t
towire_in_deleg(ARGS_TOWIRE) {
REQUIRE(rdata->type == dns_rdatatype_deleg);
REQUIRE(rdata->length != 0);
return (generic_towire_in_svcb(CALL_TOWIRE));
}
static int
compare_in_deleg(ARGS_COMPARE) {
isc_region_t region1;
isc_region_t region2;
REQUIRE(rdata1->type == rdata2->type);
REQUIRE(rdata1->rdclass == rdata2->rdclass);
REQUIRE(rdata1->type == dns_rdatatype_deleg);
REQUIRE(rdata1->rdclass == dns_rdataclass_in);
REQUIRE(rdata1->length != 0);
REQUIRE(rdata2->length != 0);
dns_rdata_toregion(rdata1, &region1);
dns_rdata_toregion(rdata2, &region2);
return (isc_region_compare(&region1, &region2));
}
static isc_result_t
fromstruct_in_deleg(ARGS_FROMSTRUCT) {
dns_rdata_in_deleg_t *deleg = source;
REQUIRE(type == dns_rdatatype_deleg);
REQUIRE(rdclass == dns_rdataclass_in);
REQUIRE(deleg != NULL);
REQUIRE(deleg->common.rdtype == type);
REQUIRE(deleg->common.rdclass == rdclass);
return (generic_fromstruct_in_svcb(CALL_FROMSTRUCT));
}
static isc_result_t
tostruct_in_deleg(ARGS_TOSTRUCT) {
dns_rdata_in_deleg_t *deleg = target;
REQUIRE(rdata->rdclass == dns_rdataclass_in);
REQUIRE(rdata->type == dns_rdatatype_deleg);
REQUIRE(deleg != NULL);
REQUIRE(rdata->length != 0);
return (generic_tostruct_in_svcb(CALL_TOSTRUCT));
}
static void
freestruct_in_deleg(ARGS_FREESTRUCT) {
dns_rdata_in_deleg_t *deleg = source;
REQUIRE(deleg != NULL);
REQUIRE(deleg->common.rdclass == dns_rdataclass_in);
REQUIRE(deleg->common.rdtype == dns_rdatatype_deleg);
generic_freestruct_in_svcb(CALL_FREESTRUCT);
}
static isc_result_t
additionaldata_in_deleg(ARGS_ADDLDATA) {
REQUIRE(rdata->type == dns_rdatatype_deleg);
REQUIRE(rdata->rdclass == dns_rdataclass_in);
return (generic_additionaldata_in_svcb(CALL_ADDLDATA));
}
static isc_result_t
digest_in_deleg(ARGS_DIGEST) {
isc_region_t region1;
REQUIRE(rdata->type == dns_rdatatype_deleg);
REQUIRE(rdata->rdclass == dns_rdataclass_in);
dns_rdata_toregion(rdata, &region1);
return ((digest)(arg, &region1));
}
static bool
checkowner_in_deleg(ARGS_CHECKOWNER) {
REQUIRE(type == dns_rdatatype_deleg);
REQUIRE(rdclass == dns_rdataclass_in);
return (true);
}
static bool
checknames_in_deleg(ARGS_CHECKNAMES) {
REQUIRE(rdata->type == dns_rdatatype_deleg);
REQUIRE(rdata->rdclass == dns_rdataclass_in);
return (generic_checknames_in_svcb(CALL_CHECKNAMES));
}
static int
casecompare_in_deleg(ARGS_COMPARE) {
return (compare_in_deleg(rdata1, rdata2));
}
isc_result_t
dns_rdata_in_deleg_first(dns_rdata_in_deleg_t *deleg) {
REQUIRE(deleg != NULL);
REQUIRE(deleg->common.rdtype == dns_rdatatype_deleg);
REQUIRE(deleg->common.rdclass == dns_rdataclass_in);
return (generic_rdata_in_svcb_first(deleg));
}
isc_result_t
dns_rdata_in_deleg_next(dns_rdata_in_deleg_t *deleg) {
REQUIRE(deleg != NULL);
REQUIRE(deleg->common.rdtype == dns_rdatatype_deleg);
REQUIRE(deleg->common.rdclass == dns_rdataclass_in);
return (generic_rdata_in_svcb_next(deleg));
}
void
dns_rdata_in_deleg_current(dns_rdata_in_deleg_t *deleg, isc_region_t *region) {
REQUIRE(deleg != NULL);
REQUIRE(deleg->common.rdtype == dns_rdatatype_deleg);
REQUIRE(deleg->common.rdclass == dns_rdataclass_in);
REQUIRE(region != NULL);
generic_rdata_in_svcb_current(deleg, region);
}
+32
View File
@@ -0,0 +1,32 @@
/*
* 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.
*/
#pragma once
/*!
* \brief Per draft-wesplaap-deleg-01
*/
#include <isc/result.h>
#include <isc/region.h>
typedef struct dns_rdata_in_svcb dns_rdata_in_deleg_t;
isc_result_t
dns_rdata_in_deleg_first(dns_rdata_in_deleg_t *);
isc_result_t
dns_rdata_in_deleg_next(dns_rdata_in_deleg_t *);
void
dns_rdata_in_deleg_current(dns_rdata_in_deleg_t *, isc_region_t *);
+131 -30
View File
@@ -3417,7 +3417,6 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
dns_forwarder_t *fwd;
dns_adbaddrinfo_t *ai;
bool all_bad;
dns_rdata_ns_t ns;
bool need_alternate = false;
bool all_spilled = false;
unsigned int no_addresses = 0;
@@ -3600,35 +3599,76 @@ normal_nses:
bool overquota = false;
unsigned int static_stub = 0;
dns_rdataset_current(&fctx->nameservers, &rdata);
/*
* Extract the name from the NS record.
*/
result = dns_rdata_tostruct(&rdata, &ns, NULL);
if (result != ISC_R_SUCCESS) {
continue;
}
switch (fctx->nameservers.type) {
case dns_rdatatype_ns: { /**/ }
dns_rdata_ns_t ns;
if (STATICSTUB(&fctx->nameservers) &&
dns_name_equal(&ns.name, fctx->domain))
{
static_stub = DNS_ADBFIND_STATICSTUB;
}
dns_rdataset_current(&fctx->nameservers, &rdata);
/*
* Extract the name from the NS record.
*/
result = dns_rdata_tostruct(&rdata, &ns, NULL);
if (result != ISC_R_SUCCESS) {
continue;
}
if (no_addresses > NS_FAIL_LIMIT &&
dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT)
{
stdoptions |= DNS_ADBFIND_NOFETCH;
}
findname(fctx, &ns.name, 0, stdoptions | static_stub, 0, now,
&overquota, &need_alternate, &no_addresses);
if (STATICSTUB(&fctx->nameservers) &&
dns_name_equal(&ns.name, fctx->domain))
{
static_stub = DNS_ADBFIND_STATICSTUB;
}
if (!overquota) {
all_spilled = false;
}
if (no_addresses > NS_FAIL_LIMIT &&
dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT)
{
stdoptions |= DNS_ADBFIND_NOFETCH;
}
findname(fctx, &ns.name, 0, stdoptions | static_stub, 0, now,
&overquota, &need_alternate, &no_addresses);
dns_rdata_reset(&rdata);
dns_rdata_freestruct(&ns);
if (!overquota) {
all_spilled = false;
}
dns_rdata_reset(&rdata);
dns_rdata_freestruct(&ns);
break;
case dns_rdatatype_deleg: { /**/ }
dns_rdata_in_deleg_t deleg;
dns_rdataset_current(&fctx->nameservers, &rdata);
/*
* Extract the name from the NS record.
*/
result = dns_rdata_tostruct(&rdata, &deleg, NULL);
if (result != ISC_R_SUCCESS) {
continue;
}
if (STATICSTUB(&fctx->nameservers) &&
dns_name_equal(&deleg.svcdomain, fctx->domain))
{
static_stub = DNS_ADBFIND_STATICSTUB;
}
if (no_addresses > NS_FAIL_LIMIT &&
dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT)
{
stdoptions |= DNS_ADBFIND_NOFETCH;
}
findname(fctx, &deleg.svcdomain, 0, stdoptions | static_stub, 0, now,
&overquota, &need_alternate, &no_addresses);
if (!overquota) {
all_spilled = false;
}
dns_rdata_reset(&rdata);
dns_rdata_freestruct(&ns);
break;
default:
break;
}
if (++ns_processed >= NS_PROCESSING_LIMIT) {
result = ISC_R_NOMORE;
@@ -3713,7 +3753,8 @@ out:
result = isc_time_nowplusinterval(&expire, &i);
if (badcache &&
(fctx->type == dns_rdatatype_dnskey ||
fctx->type == dns_rdatatype_ds) &&
fctx->type == dns_rdatatype_ds ||
fctx->type == dns_rdatatype_deleg) &&
result == ISC_R_SUCCESS)
{
dns_resolver_addbadcache(res, fctx->name,
@@ -5314,7 +5355,8 @@ validated(void *arg) {
tresult = isc_time_nowplusinterval(&expire, &i);
if (negative &&
(fctx->type == dns_rdatatype_dnskey ||
fctx->type == dns_rdatatype_ds) &&
fctx->type == dns_rdatatype_ds ||
fctx->type == dns_rdatatype_deleg) &&
tresult == ISC_R_SUCCESS)
{
dns_resolver_addbadcache(res, fctx->name,
@@ -5337,6 +5379,7 @@ validated(void *arg) {
/*
* Cache DS NXDOMAIN separately to other types.
* FIXME: What to do about DELEG?
*/
if (message->rcode == dns_rcode_nxdomain &&
fctx->type != dns_rdatatype_ds)
@@ -8879,7 +8922,7 @@ rctx_answer_none(respctx_t *rctx) {
*/
if (rctx->negative &&
rctx->query->rmessage->rcode == dns_rcode_noerror &&
fctx->type == dns_rdatatype_ds && rctx->soa_name != NULL &&
(fctx->type == dns_rdatatype_ds || fctx->type == dns_rdatatype_deleg) && rctx->soa_name != NULL &&
dns_name_equal(rctx->soa_name, fctx->name) &&
!dns_name_equal(fctx->name, dns_rootname))
{
@@ -9097,6 +9140,7 @@ rctx_ncache(respctx_t *rctx) {
/*
* Cache DS NXDOMAIN separately to other types.
* TODO: What to do about DELEG?
*/
if (rctx->query->rmessage->rcode == dns_rcode_nxdomain &&
fctx->type != dns_rdatatype_ds)
@@ -9251,6 +9295,63 @@ rctx_authority_dnssec(respctx_t *rctx) {
rdataset->trust = dns_trust_additional;
}
break;
case dns_rdatatype_deleg:
/*
* DELEG or SIG DELEG.
*
* These should only be here if this is
* a referral, and there should only be
* one DS RRset.
*/
if (rctx->ns_name == NULL) {
log_formerr(fctx, "DELEG with no "
"referral");
rctx->result = DNS_R_FORMERR;
return (ISC_R_COMPLETE);
}
if (rdataset->type == dns_rdatatype_deleg) {
if (rctx->ds_name != NULL &&
name != rctx->ds_name)
{
log_formerr(fctx, "DS doesn't "
"match "
"referral "
"(NS)");
rctx->result = DNS_R_FORMERR;
return (ISC_R_COMPLETE);
}
rctx->ds_name = name;
}
name->attributes.cache = true;
rdataset->attributes |= DNS_RDATASETATTR_CACHE;
/* FIXME: NTA handling? */
/* if ((fctx->options & DNS_FETCHOPT_NONTA) != 0) { */
/* checknta = false; */
/* } */
if (fctx->res->view->enablevalidation) {
result = issecuredomain(
fctx->res->view, name,
dns_rdatatype_ds, fctx->now,
checknta, NULL, &secure_domain);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
if (secure_domain) {
rdataset->trust =
dns_trust_pending_answer;
} else if (rctx->aa) {
rdataset->trust =
dns_trust_authauthority;
} else if (ISFORWARDER(fctx->addrinfo)) {
rdataset->trust = dns_trust_answer;
} else {
rdataset->trust = dns_trust_additional;
}
break;
default:
continue;
}
@@ -10450,7 +10551,7 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
/* XXXRTH Check for meta type */
if (domain != NULL) {
REQUIRE(DNS_RDATASET_VALID(nameservers));
REQUIRE(nameservers->type == dns_rdatatype_ns);
REQUIRE(nameservers->type == dns_rdatatype_ns || nameservers->type == dns_rdatatype_deleg);
} else {
REQUIRE(nameservers == NULL);
}
+1 -1
View File
@@ -1413,7 +1413,7 @@ add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
* as they are handled elsewhere.
*/
if ((type == dns_rdatatype_rrsig) ||
(cut && type != dns_rdatatype_ds))
(cut && type != dns_rdatatype_ds && type != dns_rdatatype_deleg))
{
continue;
}
+28 -8
View File
@@ -3254,7 +3254,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ds,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS) {
goto checkfordname;
goto checkfordeleg;
}
dns_rdataset_disassociate(&rdataset);
@@ -3268,6 +3268,24 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
dns_zone_log(zone, level, "DS not at delegation point (%s)",
namebuf);
checkfordeleg:
result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_deleg,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS) {
goto checkfordname;
}
dns_rdataset_disassociate(&rdataset);
if (zone->type == dns_zone_primary) {
level = ISC_LOG_ERROR;
ok = false;
} else {
level = ISC_LOG_WARNING;
}
dns_name_format(name, namebuf, sizeof(namebuf));
dns_zone_log(zone, level, "DELEG not at delegation point (%s)",
namebuf);
checkfordname:
result = dns_db_findrdataset(db, node, NULL,
dns_rdatatype_dname, 0, 0,
@@ -7520,7 +7538,7 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
bool offlineksk = false;
isc_buffer_t buffer;
unsigned char data[1024];
bool seen_soa, seen_ns, seen_rr, seen_nsec, seen_nsec3, seen_ds;
bool seen_soa = false, seen_ns = false, seen_rr = false, seen_nsec = false, seen_nsec3 = false, seen_ds = false, seen_deleg ISC_ATTR_UNUSED = false;
if (zone->kasp != NULL) {
offlineksk = dns_kasp_offlineksk(zone->kasp);
@@ -7536,7 +7554,6 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
dns_rdataset_init(&rdataset);
isc_buffer_init(&buffer, data, sizeof(data));
seen_rr = seen_soa = seen_ns = seen_nsec = seen_nsec3 = seen_ds = false;
for (result = dns_rdatasetiter_first(iterator); result == ISC_R_SUCCESS;
result = dns_rdatasetiter_next(iterator))
{
@@ -7547,6 +7564,8 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
seen_ns = true;
} else if (rdataset.type == dns_rdatatype_ds) {
seen_ds = true;
} else if (rdataset.type == dns_rdatatype_deleg) {
seen_deleg = true;
} else if (rdataset.type == dns_rdatatype_nsec) {
seen_nsec = true;
} else if (rdataset.type == dns_rdatatype_nsec3) {
@@ -7616,7 +7635,7 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
}
}
if (seen_ns && !seen_soa && rdataset.type != dns_rdatatype_ds &&
if (seen_ns && !seen_soa && rdataset.type != dns_rdatatype_ds && rdataset.type != dns_rdatatype_deleg &&
rdataset.type != dns_rdatatype_nsec)
{
goto next_rdataset;
@@ -8318,8 +8337,8 @@ zone_nsec3chain(dns_zone_t *zone) {
unsigned int nkeys = 0;
uint32_t nodes;
bool unsecure = false;
bool seen_soa, seen_ns, seen_dname, seen_ds;
bool seen_nsec, seen_nsec3, seen_rr;
bool seen_soa = false, seen_ns = false, seen_dname = false, seen_ds = false, seen_deleg ISC_ATTR_UNUSED = false;
bool seen_nsec = false, seen_nsec3 = false, seen_rr = false;
dns_rdatasetiter_t *iterator = NULL;
bool buildnsecchain;
bool updatensec = false;
@@ -8498,7 +8517,6 @@ zone_nsec3chain(dns_zone_t *zone) {
goto failure;
}
seen_soa = seen_ns = seen_dname = seen_ds = seen_nsec = false;
for (result = dns_rdatasetiter_first(iterator);
result == ISC_R_SUCCESS;
result = dns_rdatasetiter_next(iterator))
@@ -8513,6 +8531,8 @@ zone_nsec3chain(dns_zone_t *zone) {
seen_dname = true;
} else if (rdataset.type == dns_rdatatype_ds) {
seen_ds = true;
} else if (rdataset.type == dns_rdatatype_deleg) {
seen_deleg = true;
} else if (rdataset.type == dns_rdatatype_nsec) {
seen_nsec = true;
}
@@ -20940,7 +20960,7 @@ checkds_done(void *arg) {
for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
rdataset = ISC_LIST_NEXT(rdataset, link))
{
if (rdataset->type != dns_rdatatype_ds) {
if (rdataset->type != dns_rdatatype_ds && rdataset->type != dns_rdatatype_deleg) {
goto next;
}
+2 -1
View File
@@ -742,6 +742,7 @@ verifynsec3(const vctx_t *vctx, const dns_name_t *name,
dns_rdatatype_nsec3, 0, 0,
&rdataset, NULL);
}
/* FIXME: WTH does this do? */
if (result != ISC_R_SUCCESS &&
(!delegation || (empty && !optout) ||
(!empty && dns_nsec_isset(types, dns_rdatatype_ds))))
@@ -939,7 +940,7 @@ verifynode(vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
* other than NSEC and DS is not signed at a delegation.
*/
if (rdataset.type != dns_rdatatype_rrsig &&
(!delegation || rdataset.type == dns_rdatatype_ds ||
(!delegation || rdataset.type == dns_rdatatype_ds || rdataset.type == dns_rdatatype_deleg ||
rdataset.type == dns_rdatatype_nsec))
{
result = verifyset(vctx, &rdataset, name, node, dstkeys,
+165 -4
View File
@@ -458,6 +458,9 @@ query_delegation_recurse(query_ctx_t *qctx);
static void
query_addds(query_ctx_t *qctx);
static void
query_adddeleg(query_ctx_t *qctx);
static isc_result_t
query_nodata(query_ctx_t *qctx, isc_result_t result);
@@ -5503,7 +5506,7 @@ ns__query_start(query_ctx_t *qctx) {
qctx->qtype, qctx->options, &qctx->zone, &qctx->db,
&qctx->version, &qctx->is_zone);
if ((result != ISC_R_SUCCESS || !qctx->is_zone) &&
qctx->qtype == dns_rdatatype_ds && !RECURSIONOK(qctx->client) &&
(qctx->qtype == dns_rdatatype_ds || qctx->qtype == dns_rdatatype_deleg) && !RECURSIONOK(qctx->client) &&
qctx->options.noexact)
{
/*
@@ -6293,7 +6296,7 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
/*
* Invoke the resolver.
*/
REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
REQUIRE(nameservers == NULL || (nameservers->type == dns_rdatatype_ns || nameservers->type == dns_rdatatype_deleg));
REQUIRE(FETCH_RECTYPE_NORMAL(client) == NULL);
rdataset = ns_client_newrdataset(client);
@@ -8516,7 +8519,8 @@ query_prepare_delegation_response(query_ctx_t *qctx) {
/*
* qctx->fname could be released in query_addrrset(), so save a copy of
* it here in case we need it.
* it here in case we need it. The save name is used for both DS and
* DELEG lookups.
*/
dns_fixedname_init(&qctx->dsname);
dns_name_copy(qctx->fname, dns_fixedname_name(&qctx->dsname));
@@ -8550,6 +8554,11 @@ query_prepare_delegation_response(query_ctx_t *qctx) {
*/
query_addds(qctx);
/*
* Add DELEG/NSEC(3) record(s) if needed.
*/
query_adddeleg(qctx);
return (ns_query_done(qctx));
cleanup:
@@ -8573,7 +8582,7 @@ query_zone_delegation(query_ctx_t *qctx) {
* authoritative for the child zone
*/
if (!RECURSIONOK(qctx->client) &&
(qctx->options.noexact && qctx->qtype == dns_rdatatype_ds))
(qctx->options.noexact && (qctx->qtype == dns_rdatatype_ds || qctx->qtype == dns_rdatatype_deleg)))
{
dns_db_t *tdb = NULL;
dns_zone_t *tzone = NULL;
@@ -8955,6 +8964,158 @@ cleanup:
}
}
/*%
* Add DELEG/NSEC(3) record(s) if needed.
*/
static void
query_adddeleg(query_ctx_t *qctx) {
ns_client_t *client = qctx->client;
dns_fixedname_t fixed;
dns_name_t *fname = NULL;
dns_name_t *rname = NULL;
dns_name_t *name;
dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
isc_buffer_t *dbuf, b;
isc_result_t result;
unsigned int count;
CTRACE(ISC_LOG_DEBUG(3), "query_adddeleg");
/*
* DELEG not needed.
*/
if (!WANTDNSSEC(client)) {
return;
}
/*
* We'll need some resources...
*/
rdataset = ns_client_newrdataset(client);
sigrdataset = ns_client_newrdataset(client);
/*
* Look for the DELEG record, which may or may not be present.
*/
result = dns_db_findrdataset(qctx->db, qctx->node, qctx->version,
dns_rdatatype_deleg, 0, client->now, rdataset,
sigrdataset);
/*
* If we didn't find it, look for an NSEC.
*/
if (result == ISC_R_NOTFOUND) {
result = dns_db_findrdataset(
qctx->db, qctx->node, qctx->version, dns_rdatatype_nsec,
0, client->now, rdataset, sigrdataset);
}
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
goto addnsec3;
}
if (!dns_rdataset_isassociated(rdataset) ||
!dns_rdataset_isassociated(sigrdataset))
{
goto addnsec3;
}
/*
* We've already added the NS record, so if the name's not there,
* we have other problems.
*/
result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* Find the delegation in the response message - it is not necessarily
* the first name in the AUTHORITY section when wildcard processing is
* involved.
*/
while (result == ISC_R_SUCCESS) {
rname = NULL;
dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
&rname);
result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
if (result == ISC_R_SUCCESS) {
break;
}
result = dns_message_nextname(client->message,
DNS_SECTION_AUTHORITY);
}
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* Add the relevant RRset (DELEG or NSEC) to the delegation.
*/
query_addrrset(qctx, &rname, &rdataset, &sigrdataset, NULL,
DNS_SECTION_AUTHORITY);
goto cleanup;
addnsec3:
if (!dns_db_iszone(qctx->db)) {
goto cleanup;
}
/*
* Add the NSEC3 which proves the DELEG does not exist.
*/
dbuf = ns_client_getnamebuf(client);
fname = ns_client_newname(client, dbuf, &b);
dns_fixedname_init(&fixed);
if (dns_rdataset_isassociated(rdataset)) {
dns_rdataset_disassociate(rdataset);
}
if (dns_rdataset_isassociated(sigrdataset)) {
dns_rdataset_disassociate(sigrdataset);
}
name = dns_fixedname_name(&qctx->dsname);
query_findclosestnsec3(name, qctx->db, qctx->version, client, rdataset,
sigrdataset, fname, true,
dns_fixedname_name(&fixed));
if (!dns_rdataset_isassociated(rdataset)) {
goto cleanup;
}
query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
DNS_SECTION_AUTHORITY);
/*
* Did we find the closest provable encloser instead?
* If so add the nearest to the closest provable encloser.
*/
if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
dns_name_getlabelsequence(name,
dns_name_countlabels(name) - count,
count, dns_fixedname_name(&fixed));
fixfname(client, &fname, &dbuf, &b);
fixrdataset(client, &rdataset);
fixrdataset(client, &sigrdataset);
if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
goto cleanup;
}
query_findclosestnsec3(dns_fixedname_name(&fixed), qctx->db,
qctx->version, client, rdataset,
sigrdataset, fname, false, NULL);
if (!dns_rdataset_isassociated(rdataset)) {
goto cleanup;
}
query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
DNS_SECTION_AUTHORITY);
}
cleanup:
if (rdataset != NULL) {
ns_client_putrdataset(client, &rdataset);
}
if (sigrdataset != NULL) {
ns_client_putrdataset(client, &sigrdataset);
}
if (fname != NULL) {
ns_client_releasename(client, &fname);
}
}
/*%
* Handle authoritative NOERROR/NODATA responses.
*/