1999-09-09 08:21:45 +00:00
|
|
|
/*
|
2011-03-12 04:59:49 +00:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
1999-09-09 08:21:45 +00:00
|
|
|
*
|
2003-12-13 04:20:44 +00:00
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
1999-09-09 08:21:45 +00:00
|
|
|
* 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/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
1999-09-09 08:21:45 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
2012-12-19 09:55:02 +11:00
|
|
|
* information regarding copyright ownership.
|
1999-09-09 08:21:45 +00:00
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file */
|
2000-06-22 22:00:42 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
2012-12-19 09:55:02 +11:00
|
|
|
#include <isc/log.h>
|
2021-10-04 17:14:53 +02:00
|
|
|
#include <isc/result.h>
|
2000-05-08 14:38:29 +00:00
|
|
|
#include <isc/string.h>
|
2000-04-28 01:12:23 +00:00
|
|
|
#include <isc/util.h>
|
1999-09-09 08:21:45 +00:00
|
|
|
|
|
|
|
#include <dns/db.h>
|
2003-09-30 06:00:40 +00:00
|
|
|
#include <dns/nsec.h>
|
1999-09-09 08:21:45 +00:00
|
|
|
#include <dns/rdata.h>
|
2000-05-02 03:54:17 +00:00
|
|
|
#include <dns/rdatalist.h>
|
1999-09-09 08:21:45 +00:00
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatasetiter.h>
|
2000-10-07 00:09:28 +00:00
|
|
|
#include <dns/rdatastruct.h>
|
1999-09-09 08:21:45 +00:00
|
|
|
|
2008-09-24 02:46:23 +00:00
|
|
|
#include <dst/dst.h>
|
|
|
|
|
2012-06-25 13:57:32 +10:00
|
|
|
void
|
|
|
|
dns_nsec_setbit(unsigned char *array, unsigned int type, unsigned int bit) {
|
2000-05-13 20:39:17 +00:00
|
|
|
unsigned int shift, mask;
|
|
|
|
|
2012-06-25 13:57:32 +10:00
|
|
|
shift = 7 - (type % 8);
|
1999-09-09 08:21:45 +00:00
|
|
|
mask = 1 << shift;
|
|
|
|
|
2000-05-13 20:39:17 +00:00
|
|
|
if (bit != 0) {
|
2012-06-25 13:57:32 +10:00
|
|
|
array[type / 8] |= mask;
|
1999-09-09 08:21:45 +00:00
|
|
|
} else {
|
2012-06-25 13:57:32 +10:00
|
|
|
array[type / 8] &= (~mask & 0xFF);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-09 08:21:45 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2012-06-25 13:57:32 +10:00
|
|
|
dns_nsec_isset(const unsigned char *array, unsigned int type) {
|
1999-09-09 08:21:45 +00:00
|
|
|
unsigned int byte, shift, mask;
|
2000-05-13 20:39:17 +00:00
|
|
|
|
2012-06-25 13:57:32 +10:00
|
|
|
byte = array[type / 8];
|
|
|
|
shift = 7 - (type % 8);
|
1999-09-09 08:21:45 +00:00
|
|
|
mask = 1 << shift;
|
2000-05-13 20:39:17 +00:00
|
|
|
|
2018-10-11 11:57:57 +02:00
|
|
|
return (byte & mask) != 0;
|
2012-06-25 13:57:32 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw,
|
|
|
|
unsigned int max_type) {
|
|
|
|
unsigned char *start = map;
|
|
|
|
unsigned int window;
|
|
|
|
int octet;
|
|
|
|
|
|
|
|
if (raw == NULL) {
|
|
|
|
return 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-06-25 13:57:32 +10:00
|
|
|
|
|
|
|
for (window = 0; window < 256; window++) {
|
|
|
|
if (window * 256 > max_type) {
|
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-13 18:16:57 +01:00
|
|
|
for (octet = 31; octet >= 0; octet--) {
|
|
|
|
if (*(raw + octet) != 0) {
|
2012-06-25 13:57:32 +10:00
|
|
|
break;
|
2020-02-13 18:16:57 +01:00
|
|
|
}
|
|
|
|
}
|
2012-06-25 13:57:32 +10:00
|
|
|
if (octet < 0) {
|
|
|
|
raw += 32;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*map++ = window;
|
|
|
|
*map++ = octet + 1;
|
|
|
|
/*
|
|
|
|
* Note: potential overlapping move.
|
|
|
|
*/
|
|
|
|
memmove(map, raw, octet + 1);
|
|
|
|
map += octet + 1;
|
|
|
|
raw += 32;
|
|
|
|
}
|
2013-12-04 12:47:23 +11:00
|
|
|
return (unsigned int)(map - start);
|
1999-09-09 08:21:45 +00:00
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t
|
2003-09-30 06:00:40 +00:00
|
|
|
dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
|
|
|
|
const dns_name_t *target, unsigned char *buffer,
|
|
|
|
dns_rdata_t *rdata) {
|
1999-09-09 08:21:45 +00:00
|
|
|
isc_result_t result;
|
|
|
|
isc_region_t r;
|
2012-06-25 13:57:32 +10:00
|
|
|
unsigned int i;
|
2003-12-13 04:20:44 +00:00
|
|
|
unsigned char *nsec_bits, *bm;
|
1999-09-09 08:21:45 +00:00
|
|
|
unsigned int max_type;
|
|
|
|
dns_rdatasetiter_t *rdsiter;
|
|
|
|
|
2019-08-08 13:52:44 +10:00
|
|
|
REQUIRE(target != NULL);
|
|
|
|
|
2003-09-30 06:00:40 +00:00
|
|
|
memset(buffer, 0, DNS_NSEC_BUFFERSIZE);
|
1999-09-09 08:21:45 +00:00
|
|
|
dns_name_toregion(target, &r);
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(buffer, r.base, r.length);
|
1999-09-09 08:21:45 +00:00
|
|
|
r.base = buffer;
|
2003-12-13 04:20:44 +00:00
|
|
|
/*
|
|
|
|
* Use the end of the space for a raw bitmap leaving enough
|
|
|
|
* space for the window identifiers and length octets.
|
|
|
|
*/
|
|
|
|
bm = r.base + r.length + 512;
|
2003-09-30 06:00:40 +00:00
|
|
|
nsec_bits = r.base + r.length;
|
2012-06-25 13:57:32 +10:00
|
|
|
dns_nsec_setbit(bm, dns_rdatatype_rrsig, 1);
|
|
|
|
dns_nsec_setbit(bm, dns_rdatatype_nsec, 1);
|
2003-09-30 06:00:40 +00:00
|
|
|
max_type = dns_rdatatype_nsec;
|
1999-09-09 08:21:45 +00:00
|
|
|
rdsiter = NULL;
|
2022-11-16 10:47:40 +11:00
|
|
|
result = dns_db_allrdatasets(db, node, version, 0, 0, &rdsiter);
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
1999-09-09 08:21:45 +00:00
|
|
|
return result;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2025-03-26 22:49:03 -07:00
|
|
|
DNS_RDATASETITER_FOREACH(rdsiter) {
|
|
|
|
dns_rdataset_t rdataset = DNS_RDATASET_INIT;
|
1999-09-09 08:21:45 +00:00
|
|
|
dns_rdatasetiter_current(rdsiter, &rdataset);
|
2025-08-11 10:06:33 +02:00
|
|
|
if (!dns_rdatatype_isnsec(rdataset.type) &&
|
2008-09-24 02:46:23 +00:00
|
|
|
rdataset.type != dns_rdatatype_rrsig)
|
|
|
|
{
|
1999-09-09 08:21:45 +00:00
|
|
|
if (rdataset.type > max_type) {
|
|
|
|
max_type = rdataset.type;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-06-25 13:57:32 +10:00
|
|
|
dns_nsec_setbit(bm, rdataset.type, 1);
|
1999-09-09 08:21:45 +00:00
|
|
|
}
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
|
|
|
}
|
2025-03-26 22:49:03 -07:00
|
|
|
dns_rdatasetiter_destroy(&rdsiter);
|
1999-09-09 08:21:45 +00:00
|
|
|
|
2000-05-15 21:14:38 +00:00
|
|
|
/*
|
|
|
|
* At zone cuts, deny the existence of glue in the parent zone.
|
|
|
|
*/
|
2012-06-25 13:57:32 +10:00
|
|
|
if (dns_nsec_isset(bm, dns_rdatatype_ns) &&
|
|
|
|
!dns_nsec_isset(bm, dns_rdatatype_soa))
|
|
|
|
{
|
2003-12-13 04:20:44 +00:00
|
|
|
for (i = 0; i <= max_type; i++) {
|
2012-06-25 13:57:32 +10:00
|
|
|
if (dns_nsec_isset(bm, i) &&
|
2022-11-02 19:33:14 +01:00
|
|
|
!dns_rdatatype_iszonecutauth((dns_rdatatype_t)i))
|
|
|
|
{
|
2012-06-25 13:57:32 +10:00
|
|
|
dns_nsec_setbit(bm, i, 0);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-09 08:21:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-25 13:57:32 +10:00
|
|
|
nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type);
|
|
|
|
|
2013-12-04 12:47:23 +11:00
|
|
|
r.length = (unsigned int)(nsec_bits - r.base);
|
2003-09-30 06:00:40 +00:00
|
|
|
INSIST(r.length <= DNS_NSEC_BUFFERSIZE);
|
1999-09-09 08:21:45 +00:00
|
|
|
dns_rdata_fromregion(rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
|
|
|
|
|
2000-04-06 22:03:35 +00:00
|
|
|
return ISC_R_SUCCESS;
|
1999-09-09 08:21:45 +00:00
|
|
|
}
|
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t
|
2003-09-30 06:00:40 +00:00
|
|
|
dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
|
2016-12-30 15:45:08 +11:00
|
|
|
const dns_name_t *target, dns_ttl_t ttl) {
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
2000-10-25 04:26:57 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
2003-09-30 06:00:40 +00:00
|
|
|
unsigned char data[DNS_NSEC_BUFFERSIZE];
|
1999-09-09 08:21:45 +00:00
|
|
|
dns_rdatalist_t rdatalist;
|
|
|
|
dns_rdataset_t rdataset;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-09-09 08:21:45 +00:00
|
|
|
dns_rdataset_init(&rdataset);
|
2000-10-20 02:21:58 +00:00
|
|
|
dns_rdata_init(&rdata);
|
1999-09-09 08:21:45 +00:00
|
|
|
|
2024-12-09 15:10:53 +01:00
|
|
|
result = dns_nsec_buildrdata(db, version, node, target, data, &rdata);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto failure;
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2015-03-03 16:43:42 +11:00
|
|
|
dns_rdatalist_init(&rdatalist);
|
2000-09-12 09:55:32 +00:00
|
|
|
rdatalist.rdclass = dns_db_class(db);
|
2003-09-30 06:00:40 +00:00
|
|
|
rdatalist.type = dns_rdatatype_nsec;
|
2000-02-08 19:02:24 +00:00
|
|
|
rdatalist.ttl = ttl;
|
1999-09-09 08:21:45 +00:00
|
|
|
ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
|
2022-07-29 12:40:45 +00:00
|
|
|
dns_rdatalist_tordataset(&rdatalist, &rdataset);
|
1999-09-09 08:21:45 +00:00
|
|
|
result = dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL);
|
|
|
|
if (result == DNS_R_UNCHANGED) {
|
|
|
|
result = ISC_R_SUCCESS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2011-03-11 06:11:27 +00:00
|
|
|
|
1999-09-09 08:21:45 +00:00
|
|
|
failure:
|
|
|
|
if (dns_rdataset_isassociated(&rdataset)) {
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-09 08:21:45 +00:00
|
|
|
return result;
|
|
|
|
}
|
2000-04-13 18:08:07 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2003-09-30 06:00:40 +00:00
|
|
|
dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
|
|
|
|
dns_rdata_nsec_t nsecstruct;
|
2000-10-07 00:09:28 +00:00
|
|
|
isc_result_t result;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool present;
|
2003-12-13 04:20:44 +00:00
|
|
|
unsigned int i, len, window;
|
2000-04-13 18:08:07 +00:00
|
|
|
|
2003-09-30 06:00:40 +00:00
|
|
|
REQUIRE(nsec != NULL);
|
|
|
|
REQUIRE(nsec->type == dns_rdatatype_nsec);
|
2000-04-13 18:08:07 +00:00
|
|
|
|
2000-10-07 00:09:28 +00:00
|
|
|
/* This should never fail */
|
2003-09-30 06:00:40 +00:00
|
|
|
result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
|
2000-10-07 00:09:28 +00:00
|
|
|
INSIST(result == ISC_R_SUCCESS);
|
2008-09-24 02:46:23 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
present = false;
|
2003-12-13 04:20:44 +00:00
|
|
|
for (i = 0; i < nsecstruct.len; i += len) {
|
|
|
|
INSIST(i + 2 <= nsecstruct.len);
|
|
|
|
window = nsecstruct.typebits[i];
|
|
|
|
len = nsecstruct.typebits[i + 1];
|
|
|
|
INSIST(len > 0 && len <= 32);
|
|
|
|
i += 2;
|
|
|
|
INSIST(i + len <= nsecstruct.len);
|
2018-04-17 08:29:14 -07:00
|
|
|
if (window * 256 > type) {
|
2003-12-13 04:20:44 +00:00
|
|
|
break;
|
2018-04-17 08:29:14 -07:00
|
|
|
}
|
|
|
|
if ((window + 1) * 256 <= type) {
|
2003-12-13 04:20:44 +00:00
|
|
|
continue;
|
2018-04-17 08:29:14 -07:00
|
|
|
}
|
|
|
|
if (type < (window * 256) + len * 8) {
|
|
|
|
present = dns_nsec_isset(&nsecstruct.typebits[i],
|
|
|
|
type % 256);
|
|
|
|
}
|
2003-12-13 04:20:44 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-01-06 09:06:02 +00:00
|
|
|
dns_rdata_freestruct(&nsecstruct);
|
2000-10-07 00:09:28 +00:00
|
|
|
return present;
|
2000-04-13 18:08:07 +00:00
|
|
|
}
|
2008-09-24 02:46:23 +00:00
|
|
|
|
|
|
|
isc_result_t
|
2022-08-10 15:29:59 +02:00
|
|
|
dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
|
|
|
|
bool *answer) {
|
2008-09-24 02:46:23 +00:00
|
|
|
dns_dbnode_t *node = NULL;
|
|
|
|
dns_rdataset_t rdataset;
|
|
|
|
dns_rdata_dnskey_t dnskey;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
REQUIRE(answer != NULL);
|
|
|
|
|
|
|
|
dns_rdataset_init(&rdataset);
|
|
|
|
|
|
|
|
result = dns_db_getoriginnode(db, &node);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-09-25 04:02:39 +00:00
|
|
|
|
2008-09-24 02:46:23 +00:00
|
|
|
result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, 0,
|
|
|
|
0, &rdataset, NULL);
|
Decouple database and node lifetimes by adding node-specific vtables
All databases in the codebase follow the same structure: a database is
an associative container from DNS names to nodes, and each node is an
associative container from RR types to RR data.
Each database implementation (qpzone, qpcache, sdlz, builtin, dyndb) has
its own corresponding node type (qpznode, qpcnode, etc). However, some
code needs to work with nodes generically regardless of their specific
type - for example, to acquire locks, manage references, or
register/unregister slabs from the heap.
Currently, these generic node operations are implemented as methods in
the database vtable, which creates problematic coupling between database
and node lifetimes. If a node outlives its parent database, the node
destructor will destroy all RR data, and each RR data destructor will
try to unregister from heaps by calling a virtual function from the
database vtable. Since the database was already freed, this causes a
crash.
This commit breaks the coupling by standardizing the layout of all
database nodes, adding a dedicated vtable for node operations, and
moving node-specific methods from the database vtable to the node
vtable.
2025-06-05 11:51:29 +02:00
|
|
|
dns_db_detachnode(&node);
|
2008-09-24 02:46:23 +00:00
|
|
|
|
2011-06-10 01:51:09 +00:00
|
|
|
if (result == ISC_R_NOTFOUND) {
|
2018-04-17 08:29:14 -07:00
|
|
|
*answer = false;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-09-24 02:46:23 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2025-03-21 23:32:27 -07:00
|
|
|
bool matched = false;
|
|
|
|
DNS_RDATASET_FOREACH(&rdataset) {
|
2008-09-24 02:46:23 +00:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
|
|
|
|
dns_rdataset_current(&rdataset, &rdata);
|
|
|
|
result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
|
|
|
|
|
|
|
if (dnskey.algorithm == DST_ALG_RSAMD5 ||
|
2022-08-10 15:29:59 +02:00
|
|
|
dnskey.algorithm == DST_ALG_DSA ||
|
|
|
|
dnskey.algorithm == DST_ALG_RSASHA1)
|
|
|
|
{
|
|
|
|
bool deleted = false;
|
|
|
|
if (diff != NULL) {
|
2025-03-22 15:26:16 -07:00
|
|
|
ISC_LIST_FOREACH(diff->tuples, tuple, link) {
|
2022-08-10 15:29:59 +02:00
|
|
|
if (tuple->rdata.type !=
|
|
|
|
dns_rdatatype_dnskey ||
|
2022-11-02 19:33:14 +01:00
|
|
|
tuple->op != DNS_DIFFOP_DEL)
|
|
|
|
{
|
2022-08-10 15:29:59 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dns_rdata_compare(
|
|
|
|
&rdata, &tuple->rdata) == 0)
|
|
|
|
{
|
|
|
|
deleted = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!deleted) {
|
2025-03-21 23:32:27 -07:00
|
|
|
matched = true;
|
2022-08-10 15:29:59 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-09-24 02:46:23 +00:00
|
|
|
}
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
2025-03-21 23:32:27 -07:00
|
|
|
*answer = matched;
|
|
|
|
return ISC_R_SUCCESS;
|
2008-09-24 02:46:23 +00:00
|
|
|
}
|
2012-12-19 09:55:02 +11:00
|
|
|
|
|
|
|
/*%
|
|
|
|
* Return ISC_R_SUCCESS if we can determine that the name doesn't exist
|
|
|
|
* or we can determine whether there is data or not at the name.
|
|
|
|
* If the name does not exist return the wildcard name.
|
|
|
|
*
|
|
|
|
* Return ISC_R_IGNORE when the NSEC is not the appropriate one.
|
|
|
|
*/
|
|
|
|
isc_result_t
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name,
|
|
|
|
const dns_name_t *nsecname, dns_rdataset_t *nsecset,
|
2018-04-17 08:29:14 -07:00
|
|
|
bool *exists, bool *data, dns_name_t *wild,
|
2012-12-19 09:55:02 +11:00
|
|
|
dns_nseclog_t logit, void *arg) {
|
|
|
|
int order;
|
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_namereln_t relation;
|
|
|
|
unsigned int olabels, nlabels, labels;
|
|
|
|
dns_rdata_nsec_t nsec;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool atparent;
|
|
|
|
bool ns;
|
|
|
|
bool soa;
|
2012-12-19 09:55:02 +11:00
|
|
|
|
|
|
|
REQUIRE(exists != NULL);
|
|
|
|
REQUIRE(data != NULL);
|
|
|
|
REQUIRE(nsecset != NULL && nsecset->type == dns_rdatatype_nsec);
|
|
|
|
|
|
|
|
result = dns_rdataset_first(nsecset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC set");
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
dns_rdataset_current(nsecset, &rdata);
|
|
|
|
|
2021-11-06 09:30:48 +11:00
|
|
|
#ifdef notyet
|
|
|
|
if (!dns_nsec_typepresent(&rdata, dns_rdatatype_rrsig) ||
|
|
|
|
!dns_nsec_typepresent(&rdata, dns_rdatatype_nsec))
|
|
|
|
{
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"NSEC missing RRSIG and/or NSEC from type map");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-10 23:09:08 +11:00
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC");
|
2012-12-19 09:55:02 +11:00
|
|
|
relation = dns_name_fullcompare(name, nsecname, &order, &olabels);
|
|
|
|
|
|
|
|
if (order < 0) {
|
|
|
|
/*
|
|
|
|
* The name is not within the NSEC range.
|
|
|
|
*/
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"NSEC does not cover name, before NSEC");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (order == 0) {
|
|
|
|
/*
|
|
|
|
* The names are the same. If we are validating "."
|
|
|
|
* then atparent should not be set as there is no parent.
|
|
|
|
*/
|
|
|
|
atparent = (olabels != 1) && dns_rdatatype_atparent(type);
|
|
|
|
ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
|
|
|
|
soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa);
|
|
|
|
if (ns && !soa) {
|
|
|
|
if (!atparent) {
|
|
|
|
/*
|
|
|
|
* This NSEC record is from somewhere higher in
|
|
|
|
* the DNS, and at the parent of a delegation.
|
|
|
|
* It can not be legitimately used here.
|
|
|
|
*/
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"ignoring parent nsec");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
} else if (atparent && ns && soa) {
|
|
|
|
/*
|
|
|
|
* This NSEC record is from the child.
|
|
|
|
* It can not be legitimately used here.
|
|
|
|
*/
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "ignoring child nsec");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
if (type == dns_rdatatype_cname || type == dns_rdatatype_nxt ||
|
|
|
|
type == dns_rdatatype_nsec || type == dns_rdatatype_key ||
|
|
|
|
!dns_nsec_typepresent(&rdata, dns_rdatatype_cname))
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
*exists = true;
|
2012-12-19 09:55:02 +11:00
|
|
|
*data = dns_nsec_typepresent(&rdata, type);
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"nsec proves name exists (owner) data=%d",
|
|
|
|
*data);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (relation == dns_namereln_subdomain &&
|
2018-07-06 15:07:59 +10:00
|
|
|
dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
|
2012-12-19 09:55:02 +11:00
|
|
|
!dns_nsec_typepresent(&rdata, dns_rdatatype_soa))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This NSEC record is from somewhere higher in
|
2018-07-05 12:58:49 +02:00
|
|
|
* the DNS, and at the parent of a delegation or
|
|
|
|
* at a DNAME.
|
2012-12-19 09:55:02 +11:00
|
|
|
* It can not be legitimately used here.
|
|
|
|
*/
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
|
2018-07-06 15:07:59 +10:00
|
|
|
if (relation == dns_namereln_subdomain &&
|
|
|
|
dns_nsec_typepresent(&rdata, dns_rdatatype_dname))
|
|
|
|
{
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "nsec proves covered by dname");
|
2018-04-17 08:29:14 -07:00
|
|
|
*exists = false;
|
2018-07-06 15:07:59 +10:00
|
|
|
return DNS_R_DNAME;
|
|
|
|
}
|
|
|
|
|
2012-12-19 09:55:02 +11:00
|
|
|
result = dns_rdata_tostruct(&rdata, &nsec, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return result;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-12-19 09:55:02 +11:00
|
|
|
relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels);
|
|
|
|
if (order == 0) {
|
|
|
|
dns_rdata_freestruct(&nsec);
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"ignoring nsec matches next name");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) {
|
|
|
|
/*
|
|
|
|
* The name is not within the NSEC range.
|
|
|
|
*/
|
|
|
|
dns_rdata_freestruct(&nsec);
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"ignoring nsec because name is past end of range");
|
|
|
|
return ISC_R_IGNORE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (order > 0 && relation == dns_namereln_subdomain) {
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"nsec proves name exist (empty)");
|
|
|
|
dns_rdata_freestruct(&nsec);
|
2018-04-17 08:29:14 -07:00
|
|
|
*exists = true;
|
|
|
|
*data = false;
|
2012-12-19 09:55:02 +11:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
if (wild != NULL) {
|
|
|
|
dns_name_t common;
|
2025-02-21 12:09:39 +01:00
|
|
|
dns_name_init(&common);
|
2012-12-19 09:55:02 +11:00
|
|
|
if (olabels > nlabels) {
|
|
|
|
labels = dns_name_countlabels(nsecname);
|
|
|
|
dns_name_getlabelsequence(nsecname, labels - olabels,
|
|
|
|
olabels, &common);
|
|
|
|
} else {
|
|
|
|
labels = dns_name_countlabels(&nsec.next);
|
|
|
|
dns_name_getlabelsequence(&nsec.next, labels - nlabels,
|
|
|
|
nlabels, &common);
|
|
|
|
}
|
2025-02-21 00:56:47 -08:00
|
|
|
result = dns_name_concatenate(dns_wildcardname, &common, wild);
|
2012-12-19 09:55:02 +11:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
dns_rdata_freestruct(&nsec);
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3),
|
|
|
|
"failure generating wildcard name");
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dns_rdata_freestruct(&nsec);
|
|
|
|
(*logit)(arg, ISC_LOG_DEBUG(3), "nsec range ok");
|
2018-04-17 08:29:14 -07:00
|
|
|
*exists = false;
|
2012-12-19 09:55:02 +11:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2021-11-27 09:12:08 +11:00
|
|
|
|
|
|
|
bool
|
|
|
|
dns_nsec_requiredtypespresent(dns_rdataset_t *nsecset) {
|
2025-03-21 23:32:27 -07:00
|
|
|
dns_rdataset_t rdataset = DNS_RDATASET_INIT;
|
2021-11-27 09:12:08 +11:00
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(nsecset));
|
|
|
|
REQUIRE(nsecset->type == dns_rdatatype_nsec);
|
|
|
|
|
|
|
|
dns_rdataset_clone(nsecset, &rdataset);
|
|
|
|
|
2025-03-21 23:32:27 -07:00
|
|
|
DNS_RDATASET_FOREACH(&rdataset) {
|
2021-11-27 09:12:08 +11:00
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
dns_rdataset_current(&rdataset, &rdata);
|
|
|
|
if (!dns_nsec_typepresent(&rdata, dns_rdatatype_nsec) ||
|
|
|
|
!dns_nsec_typepresent(&rdata, dns_rdatatype_rrsig))
|
|
|
|
{
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
dns_rdataset_disassociate(&rdataset);
|
|
|
|
return found;
|
|
|
|
}
|