Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14271bf4e2 | ||
|
|
db6e91497c | ||
|
|
b735f2e821 | ||
|
|
e39d265a99 | ||
|
|
8f03f31106 | ||
|
|
d3d981f38e | ||
|
|
6c291971db | ||
|
|
d61dc02a7c | ||
|
|
503c7a86fe | ||
|
|
6876c06918 | ||
|
|
fdb9a24d18 | ||
|
|
ea33257ad0 | ||
|
|
dd971ad4e4 | ||
|
|
8368ef5ae7 | ||
|
|
d8778caec7 | ||
|
|
a8dd267bd0 | ||
|
|
606d30796e | ||
|
|
37ff0aa9c0 | ||
|
|
1c51d44d82 | ||
|
|
3b0b658a52 | ||
|
|
ecde0ea2d7 | ||
|
|
7d98aba3ac | ||
|
|
24eaff7adc | ||
|
|
025ef4d7b8 | ||
|
|
9cfe9f5eb7 | ||
|
|
e6c07b3386 | ||
|
|
1a58bd2113 | ||
|
|
42799ae81f | ||
|
|
de519cd1c9 | ||
|
|
496f7963cd | ||
|
|
98fc14dc75 | ||
|
|
3397212df3 | ||
|
|
947ca25663 | ||
|
|
6c271f6328 | ||
|
|
6ac4cfb948 | ||
|
|
f6f9645ed1 | ||
|
|
1f674ef42e | ||
|
|
f50753f303 | ||
|
|
45ee3715e1 | ||
|
|
7f613c207f | ||
|
|
24ffbdcfea | ||
|
|
e66dc07c68 | ||
|
|
e763d6637f | ||
|
|
334ea1269f | ||
|
|
3309863c97 | ||
|
|
8b3d2e5633 | ||
|
|
3973c2e8c3 | ||
|
|
ecef45bf18 | ||
|
|
33a0cc9823 | ||
|
|
bd711bb839 |
+16
-2
@@ -289,6 +289,7 @@ help(void) {
|
||||
" form of answers - global "
|
||||
"option)\n"
|
||||
" +[no]showbadcookie (Show BADCOOKIE message)\n"
|
||||
" +[no]showbadvers (Show BADVERS message)\n"
|
||||
" +[no]showsearch (Search with intermediate "
|
||||
"results)\n"
|
||||
" +[no]split=## (Split hex/base64 fields "
|
||||
@@ -1772,6 +1773,8 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
|
||||
FULLCHECK("edns");
|
||||
if (!state) {
|
||||
lookup->edns = -1;
|
||||
lookup->original_edns =
|
||||
-1;
|
||||
break;
|
||||
}
|
||||
if (value == NULL) {
|
||||
@@ -1788,6 +1791,7 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
|
||||
goto exit_or_usage;
|
||||
}
|
||||
lookup->edns = num;
|
||||
lookup->original_edns = num;
|
||||
break;
|
||||
case 'f':
|
||||
FULLCHECK("ednsflags");
|
||||
@@ -2306,8 +2310,18 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
|
||||
case 'w': /* showsearch */
|
||||
switch (cmd[4]) {
|
||||
case 'b':
|
||||
FULLCHECK("showbadcookie");
|
||||
lookup->showbadcookie = state;
|
||||
switch (cmd[7]) {
|
||||
case 'c':
|
||||
FULLCHECK("showbadcookie");
|
||||
lookup->showbadcookie = state;
|
||||
break;
|
||||
case 'v':
|
||||
FULLCHECK("showbadvers");
|
||||
lookup->showbadvers = state;
|
||||
break;
|
||||
default:
|
||||
goto invalid_option;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
FULLCHECK("showsearch");
|
||||
|
||||
@@ -614,6 +614,12 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
|
||||
BADCOOKIE rcode before retrying the request or not. The default
|
||||
is to not show the messages.
|
||||
|
||||
.. option:: +showbadvers, +noshowbadvers
|
||||
|
||||
This option toggles whether to show the message containing the
|
||||
BADVERS rcode before retrying the request or not. The default
|
||||
is to not show the messages.
|
||||
|
||||
.. option:: +showsearch, +noshowsearch
|
||||
|
||||
This option performs [or does not perform] a search showing intermediate results.
|
||||
|
||||
+11
-1
@@ -605,6 +605,7 @@ make_empty_lookup(void) {
|
||||
.idnout = idnout,
|
||||
.udpsize = -1,
|
||||
.edns = -1,
|
||||
.original_edns = -1,
|
||||
.recurse = true,
|
||||
.retries = tries,
|
||||
.comments = true,
|
||||
@@ -738,6 +739,7 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
|
||||
}
|
||||
|
||||
looknew->showbadcookie = lookold->showbadcookie;
|
||||
looknew->showbadvers = lookold->showbadvers;
|
||||
looknew->sendcookie = lookold->sendcookie;
|
||||
looknew->seenbadcookie = lookold->seenbadcookie;
|
||||
looknew->badcookie = lookold->badcookie;
|
||||
@@ -764,6 +766,7 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
|
||||
looknew->idnout = lookold->idnout;
|
||||
looknew->udpsize = lookold->udpsize;
|
||||
looknew->edns = lookold->edns;
|
||||
looknew->original_edns = lookold->original_edns;
|
||||
looknew->recurse = lookold->recurse;
|
||||
looknew->aaonly = lookold->aaonly;
|
||||
looknew->adflag = lookold->adflag;
|
||||
@@ -1938,6 +1941,7 @@ followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section) {
|
||||
}
|
||||
domain = dns_fixedname_name(&lookup->fdomain);
|
||||
dns_name_copy(name, domain);
|
||||
lookup->edns = lookup->original_edns;
|
||||
}
|
||||
debug("adding server %s", namestr);
|
||||
num = getaddresses(lookup, namestr, &lresult);
|
||||
@@ -2456,7 +2460,8 @@ setup_lookup(dig_lookup_t *lookup) {
|
||||
lookup->udpsize = DEFAULT_EDNS_BUFSIZE;
|
||||
}
|
||||
if (lookup->edns < 0) {
|
||||
lookup->edns = DEFAULT_EDNS_VERSION;
|
||||
lookup->original_edns = lookup->edns =
|
||||
DEFAULT_EDNS_VERSION;
|
||||
}
|
||||
|
||||
if (lookup->nsid) {
|
||||
@@ -4300,6 +4305,11 @@ recv_done(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
||||
if (msg->rcode == dns_rcode_badvers && msg->opt != NULL &&
|
||||
(newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg)
|
||||
{
|
||||
if (l->showbadvers) {
|
||||
dighost_printmessage(query, &b, msg, true);
|
||||
dighost_received(isc_buffer_usedlength(&b), &peer,
|
||||
query);
|
||||
}
|
||||
/*
|
||||
* Add minimum EDNS version required checks here if needed.
|
||||
*/
|
||||
|
||||
+4
-3
@@ -117,9 +117,9 @@ struct dig_lookup {
|
||||
section_answer, section_authority, section_question,
|
||||
seenbadcookie, sendcookie, servfail_stops,
|
||||
setqid, /*% use a speciied query ID */
|
||||
showbadcookie, stats, tcflag, tcp_keepalive, tcp_mode,
|
||||
tcp_mode_set, tls_mode, /*% connect using TLS */
|
||||
trace, /*% dig +trace */
|
||||
showbadcookie, showbadvers, stats, tcflag, tcp_keepalive,
|
||||
tcp_mode, tcp_mode_set, tls_mode, /*% connect using TLS */
|
||||
trace, /*% dig +trace */
|
||||
trace_root, /*% initial query for either +trace or +nssearch */
|
||||
ttlunits, use_usec, waiting_connect, zflag;
|
||||
char textname[MXNAME]; /*% Name we're going to be looking up */
|
||||
@@ -148,6 +148,7 @@ struct dig_lookup {
|
||||
int nsfound;
|
||||
int16_t udpsize;
|
||||
int16_t edns;
|
||||
int16_t original_edns;
|
||||
int16_t padding;
|
||||
uint32_t ixfr_serial;
|
||||
isc_buffer_t rdatabuf;
|
||||
|
||||
+1
-2
@@ -246,8 +246,7 @@ printsection(dns_message_t *msg, dns_section_t sectionid,
|
||||
(list_type == dns_rdatatype_any ||
|
||||
rdataset->type == list_type)) ||
|
||||
(list_addresses &&
|
||||
(rdataset->type == dns_rdatatype_a ||
|
||||
rdataset->type == dns_rdatatype_aaaa ||
|
||||
(dns_rdatatype_isaddr(rdataset->type) ||
|
||||
rdataset->type == dns_rdatatype_ns ||
|
||||
rdataset->type == dns_rdatatype_ptr))))
|
||||
{
|
||||
|
||||
@@ -736,7 +736,6 @@ controlkeylist_fromcfg(const cfg_obj_t *keylist, isc_mem_t *mctx,
|
||||
key->secret.length = 0;
|
||||
ISC_LINK_INIT(key, link);
|
||||
ISC_LIST_APPEND(*keyids, key, link);
|
||||
newstr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-5
@@ -3762,7 +3762,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
||||
uint32_t maxbits;
|
||||
unsigned int resopts = 0;
|
||||
dns_zone_t *zone = NULL;
|
||||
uint32_t max_clients_per_query;
|
||||
uint32_t clients_per_query, max_clients_per_query;
|
||||
bool empty_zones_enable;
|
||||
const cfg_obj_t *disablelist = NULL;
|
||||
isc_stats_t *resstats = NULL;
|
||||
@@ -5168,15 +5168,26 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->v6bias = cfg_obj_asuint32(obj) * 1000;
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "clients-per-query", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
clients_per_query = cfg_obj_asuint32(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "max-clients-per-query", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
max_clients_per_query = cfg_obj_asuint32(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "clients-per-query", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_resolver_setclientsperquery(view->resolver, cfg_obj_asuint32(obj),
|
||||
if (max_clients_per_query < clients_per_query) {
|
||||
cfg_obj_log(obj, ISC_LOG_WARNING,
|
||||
"configured clients-per-query (%u) exceeds "
|
||||
"max-clients-per-query (%u); automatically "
|
||||
"adjusting max-clients-per-query to (%u)",
|
||||
clients_per_query, max_clients_per_query,
|
||||
clients_per_query);
|
||||
max_clients_per_query = clients_per_query;
|
||||
}
|
||||
dns_resolver_setclientsperquery(view->resolver, clients_per_query,
|
||||
max_clients_per_query);
|
||||
|
||||
/*
|
||||
|
||||
@@ -28,6 +28,7 @@ options {
|
||||
} except-from {
|
||||
"example";
|
||||
};
|
||||
qname-minimization disabled; // Regression test for GL #4652
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
||||
@@ -552,16 +552,21 @@ sys.exit(1)'; then
|
||||
$DIG $DIGOPTS @10.53.0.1 tsig. >dig.out.test$n.1 || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n.1 >/dev/null || ret=1
|
||||
rndc_dumpdb ns1
|
||||
# prime cache with NS response for QNAME minimisation
|
||||
grep "$pat" ns1/named_dump.db.test$n >/dev/null || ret=1
|
||||
$DIG $DIGOPTS @10.53.0.1 NS nocookie.tsig >dig.out.test$n.2 || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n.2 >/dev/null || ret=1
|
||||
# check the disabled server response
|
||||
nextpart ns1/named.run >/dev/null
|
||||
$DIG $DIGOPTS @10.53.0.1 nocookie.tsig >dig.out.test$n.2 || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n.2 >/dev/null || ret=1
|
||||
grep 'A.10\.53\.0\.9' dig.out.test$n.2 >/dev/null || ret=1
|
||||
grep 'A.10\.53\.0\.10' dig.out.test$n.2 >/dev/null || ret=1
|
||||
$DIG $DIGOPTS @10.53.0.1 nocookie.tsig >dig.out.test$n.3 || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n.3 >/dev/null || ret=1
|
||||
grep 'A.10\.53\.0\.9' dig.out.test$n.3 >/dev/null || ret=1
|
||||
grep 'A.10\.53\.0\.10' dig.out.test$n.3 >/dev/null || ret=1
|
||||
nextpart ns1/named.run >named.run.test$n
|
||||
count=$(grep -c ') [0-9][0-9]* NOERROR 0' named.run.test$n)
|
||||
test $count -eq 2 || ret=1
|
||||
count=$(grep -c '^; COOKIE: ................................' named.run.test$n)
|
||||
test $count -eq 1 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
fi
|
||||
|
||||
@@ -1135,6 +1135,16 @@ if [ -x "$DIG" ]; then
|
||||
grep "; EDNS: version: 0, flags:; udp: 1232" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig +showbadvers works ($n)"
|
||||
dig_with_opts @10.53.0.3 +edns=1 +qr +showbadvers a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep "; EDNS: version: 1, flags:; udp: 1232" dig.out.test$n >/dev/null || ret=1
|
||||
grep "; EDNS: version: 0, flags:; udp: 1232" dig.out.test$n >/dev/null || ret=1
|
||||
grep -F "status: BADVERS" dig.out.test$n >/dev/null || ret=1
|
||||
grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
else
|
||||
echo_i "$DIG is needed, so skipping these dig tests"
|
||||
fi
|
||||
|
||||
@@ -64,7 +64,7 @@ for subdomain in digest-alg-unsupported ds-unsupported secure badds \
|
||||
kskonly update-nsec3 auto-nsec auto-nsec3 secure.below-cname \
|
||||
ttlpatch split-dnssec split-smart expired expiring upper lower \
|
||||
dnskey-unknown dnskey-unsupported dnskey-unsupported-2 \
|
||||
dnskey-nsec3-unknown managed-future revkey \
|
||||
dnskey-nsec3-unknown managed-future future revkey \
|
||||
dname-at-apex-nsec3 occluded rsasha1 rsasha1-1024; do
|
||||
cp "../ns3/dsset-$subdomain.example." .
|
||||
done
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
; This is a key-signing key, keyid 23640, for .
|
||||
; Created: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
; Publish: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
; Activate: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
; Revoke: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
. IN DNSKEY 257 3 13 uKwpRtMH+9iuUk/Xj6LciIP5ZckaBtXaUqxUxzJYexXjvxGZGX4470Jv hq2NCI3HBZQNaCCP/h9sluhIzRGPTA==
|
||||
@@ -0,0 +1,7 @@
|
||||
Private-key-format: v1.3
|
||||
Algorithm: 13 (ECDSAP256SHA256)
|
||||
PrivateKey: m5udfGNSijISQ8Tfp4kx09O1em4PErLUw/mCj3SKmqw=
|
||||
Created: 20250310185208
|
||||
Publish: 20250310185208
|
||||
Activate: 20250310185208
|
||||
Revoke: 20250310185208
|
||||
@@ -0,0 +1,5 @@
|
||||
; This is a zone-signing key, keyid 23768, for .
|
||||
; Created: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
; Publish: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
; Activate: 20250310185208 (Mon Mar 10 18:52:08 2025)
|
||||
. IN DNSKEY 256 3 13 TFelYtTRBWeA9A307vvuWIcaNwW4txW4RgSELtsi46ZQs24ncRxmxtFf uJuPyVXePNiE4HNI9CIowGUsn5WuBw==
|
||||
@@ -0,0 +1,37 @@
|
||||
; 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.
|
||||
|
||||
; This is a zone which has two DNSKEY records, both of which have
|
||||
; existing private key files available. They should be loaded automatically
|
||||
; and the zone correctly signed.
|
||||
;
|
||||
$TTL 30 ; 30 seconds
|
||||
. IN SOA a.root.servers.nil. each.isc.org. (
|
||||
2000042101 ; serial
|
||||
600 ; refresh (10 minutes)
|
||||
600 ; retry (10 minutes)
|
||||
1200 ; expire (20 minutes)
|
||||
600 ; minimum (10 minutes)
|
||||
)
|
||||
NS a.root-servers.nil.
|
||||
DNSKEY 256 3 13 (
|
||||
TFelYtTRBWeA9A307vvuWIcaNwW4txW4RgSELtsi46ZQ
|
||||
s24ncRxmxtFfuJuPyVXePNiE4HNI9CIowGUsn5WuBw==
|
||||
) ; ZSK; alg = ECDSAP256SHA256 ; key id = 23768
|
||||
DNSKEY 257 3 13 (
|
||||
OSmhpULEDCUzHCBeDU5uJXzkCcGuW2qrkQznKRPGhRZN
|
||||
j7ZUIGInGzM5Um5m02ULWt8tKbi55NJUeifKWegQ0g==
|
||||
) ; KSK; alg = ECDSAP256SHA256 ; key id = 22255
|
||||
DNSKEY 385 3 13 (
|
||||
uKwpRtMH+9iuUk/Xj6LciIP5ZckaBtXaUqxUxzJYexXj
|
||||
vxGZGX4470Jvhq2NCI3HBZQNaCCP/h9sluhIzRGPTA==
|
||||
) ; revoked KSK; alg = ECDSAP256SHA256 ; key id = 23768
|
||||
a.root-servers.nil. A 10.53.0.1
|
||||
@@ -1564,6 +1564,18 @@ n=$((n + 1))
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
echo_ic "revoked KSK ID collides with ZSK ($n)"
|
||||
ret=0
|
||||
# signing should fail, but should not coredump
|
||||
(
|
||||
cd signer/general || exit 0
|
||||
rm -f signed.zone
|
||||
$SIGNER -S -f signed.zone -o . test12.zone >signer.out.$n
|
||||
) && ret=1
|
||||
n=$((n + 1))
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
echo_ic "check that dnssec-signzone rejects excessive NSEC3 iterations ($n)"
|
||||
ret=0
|
||||
(
|
||||
@@ -2179,7 +2191,7 @@ echo_i "checking RRSIG query from cache ($n)"
|
||||
ret=0
|
||||
dig_with_opts normalthenrrsig.secure.example. @10.53.0.4 a >/dev/null || ret=1
|
||||
ans=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.4 rrsig) || ret=1
|
||||
expect=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.3 rrsig | grep '^A') || ret=1
|
||||
expect=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.3 rrsig | grep '^\(A\|NSEC\)') || ret=1
|
||||
test "$ans" = "$expect" || ret=1
|
||||
# also check that RA is set
|
||||
dig_with_opts normalthenrrsig.secure.example. @10.53.0.4 rrsig >dig.out.ns4.test$n || ret=1
|
||||
@@ -2859,6 +2871,19 @@ dig_with_opts +noauth expired.example. +dnssec @10.53.0.4 soa >dig.out.ns4.test$
|
||||
grep "SERVFAIL" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1
|
||||
grep "expired.example/.*: RRSIG has expired" ns4/named.run >/dev/null || ret=1
|
||||
grep "; EDE: 7 (Signature Expired): (expired.example/DNSKEY)" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
n=$((n + 1))
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
status=$((status + ret))
|
||||
echo_i "checking signatures in the future do not validate ($n)"
|
||||
ret=0
|
||||
dig_with_opts +noauth future.example. +dnssec @10.53.0.4 soa >dig.out.ns4.test$n || ret=1
|
||||
grep "SERVFAIL" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1
|
||||
grep "future.example/.*: RRSIG validity period has not begun" ns4/named.run >/dev/null || ret=1
|
||||
grep "; EDE: 8 (Signature Not Yet Valid): (future.example/DNSKEY)" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
n=$((n + 1))
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
@@ -3755,7 +3780,7 @@ status=$((status + ret))
|
||||
echo_i "checking EDE code 1 for bad alg mnemonic ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.4 badalg.secure.example >dig.out.ns4.test$n || ret=1
|
||||
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (ECDSAP256SHA256 badalg.secure.example/A)" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
grep "; EDE: 1 (Unsupported DNSKEY Algorithm): (ECDSAP256SHA256 badalg.secure.example/NSEC)" dig.out.ns4.test$n >/dev/null || ret=1
|
||||
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1
|
||||
n=$((n + 1))
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
|
||||
@@ -232,9 +232,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
dns_fixedname_init(&name);
|
||||
CHECK(dns__db_addrdataset(sampledb->db, node, version, now, rdataset,
|
||||
options, addedrdataset DNS__DB_FLARG_PASS));
|
||||
if (rdataset->type == dns_rdatatype_a ||
|
||||
rdataset->type == dns_rdatatype_aaaa)
|
||||
{
|
||||
if (dns_rdatatype_isaddr(rdataset->type)) {
|
||||
CHECK(dns_db_nodefullname(sampledb->db, node,
|
||||
dns_fixedname_name(&name)));
|
||||
CHECK(syncptrs(sampledb->inst, dns_fixedname_name(&name),
|
||||
@@ -263,9 +261,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (rdataset->type == dns_rdatatype_a ||
|
||||
rdataset->type == dns_rdatatype_aaaa)
|
||||
{
|
||||
if (dns_rdatatype_isaddr(rdataset->type)) {
|
||||
CHECK(dns_db_nodefullname(sampledb->db, node,
|
||||
dns_fixedname_name(&name)));
|
||||
CHECK(syncptrs(sampledb->inst, dns_fixedname_name(&name),
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.5;
|
||||
notify-source 10.53.0.5;
|
||||
transfer-source 10.53.0.5;
|
||||
port @PORT@;
|
||||
directory ".";
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.5; };
|
||||
listen-on-v6 { none; };
|
||||
recursion yes;
|
||||
dnssec-validation yes;
|
||||
notify yes;
|
||||
stale-answer-enable yes;
|
||||
stale-cache-enable yes;
|
||||
stale-answer-client-timeout 0;
|
||||
/* max-clients-per-query < clients-per-query */
|
||||
clients-per-query 10;
|
||||
max-clients-per-query 5;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
||||
server 10.53.0.4 {
|
||||
edns no;
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type hint;
|
||||
file "root.hint";
|
||||
};
|
||||
@@ -328,5 +328,14 @@ echo_i "$zspill clients spilled (expected $expected)"
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking a warning is logged if max-clients-per-query < clients-per-query ($n)"
|
||||
ret=0
|
||||
copy_setports ns5/named3.conf.in ns5/named.conf
|
||||
rndc_reconfig ns5 10.53.0.5
|
||||
wait_for_message ns5/named.run "configured clients-per-query (10) exceeds max-clients-per-query (5); automatically adjusting max-clients-per-query to (10)" || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import difflib
|
||||
import shutil
|
||||
from typing import Optional
|
||||
|
||||
@@ -98,28 +97,6 @@ def zones_equal(
|
||||
assert found_rdataset.ttl == rdataset.ttl
|
||||
|
||||
|
||||
def zone_contains(
|
||||
zone: dns.zone.Zone, rrset: dns.rrset.RRset, compare_ttl=False
|
||||
) -> bool:
|
||||
"""Check if a zone contains RRset"""
|
||||
|
||||
def compare_rrs(rr1, rrset):
|
||||
rr2 = next((other_rr for other_rr in rrset if rr1 == other_rr), None)
|
||||
if rr2 is None:
|
||||
return False
|
||||
if compare_ttl:
|
||||
return rr1.ttl == rr2.ttl
|
||||
return True
|
||||
|
||||
for _, node in zone.nodes.items():
|
||||
for rdataset in node:
|
||||
for rr in rdataset:
|
||||
if compare_rrs(rr, rrset):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_executable(cmd: str, errmsg: str) -> None:
|
||||
executable = shutil.which(cmd)
|
||||
assert executable is not None, errmsg
|
||||
@@ -151,32 +128,3 @@ def is_response_to(response: dns.message.Message, query: dns.message.Message) ->
|
||||
single_question(response)
|
||||
single_question(query)
|
||||
assert query.is_response(response), str(response)
|
||||
|
||||
|
||||
def file_contents_contain(file, substr):
|
||||
with open(file, "r", encoding="utf-8") as fp:
|
||||
for line in fp:
|
||||
if f"{substr}" in line:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def file_contents_equal(file1, file2):
|
||||
def normalize_line(line):
|
||||
# remove trailing&leading whitespace and replace multiple whitespaces
|
||||
return " ".join(line.split())
|
||||
|
||||
def read_lines(file_path):
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
return [normalize_line(line) for line in file.readlines()]
|
||||
|
||||
lines1 = read_lines(file1)
|
||||
lines2 = read_lines(file2)
|
||||
|
||||
differ = difflib.Differ()
|
||||
diff = differ.compare(lines1, lines2)
|
||||
|
||||
for line in diff:
|
||||
assert not line.startswith("+ ") and not line.startswith(
|
||||
"- "
|
||||
), f'file contents of "{file1}" and "{file2}" differ'
|
||||
|
||||
@@ -10,34 +10,24 @@
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from functools import total_ordering
|
||||
import glob
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from typing import List, Optional, Union
|
||||
from typing import Optional, Union
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import dns
|
||||
import dns.tsig
|
||||
import isctest.log
|
||||
import isctest.query
|
||||
|
||||
DEFAULT_TTL = 300
|
||||
|
||||
NEXT_KEY_EVENT_THRESHOLD = 100
|
||||
|
||||
|
||||
def _query(server, qname, qtype, tsig=None):
|
||||
def _query(server, qname, qtype):
|
||||
query = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True)
|
||||
|
||||
if tsig is not None:
|
||||
tsigkey = tsig.split(":")
|
||||
keyring = dns.tsig.Key(tsigkey[1], tsigkey[2], tsigkey[0])
|
||||
query.use_tsig(keyring)
|
||||
|
||||
try:
|
||||
response = isctest.query.tcp(query, server.ip, server.ports.dns, timeout=3)
|
||||
except dns.exception.Timeout:
|
||||
@@ -47,158 +37,6 @@ def _query(server, qname, qtype, tsig=None):
|
||||
return response
|
||||
|
||||
|
||||
class KeyProperties:
|
||||
"""
|
||||
Represent the (expected) properties a key should have.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, properties: dict, metadata: dict, timing: dict):
|
||||
self.name = name
|
||||
self.key = None
|
||||
self.properties = properties
|
||||
self.metadata = metadata
|
||||
self.timing = timing
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
@staticmethod
|
||||
def default(with_state=True) -> "KeyProperties":
|
||||
result = KeyProperties.__new__(KeyProperties)
|
||||
result.name = "DEFAULT"
|
||||
result.key = None
|
||||
result.timing = {}
|
||||
result.properties = {
|
||||
"expect": True,
|
||||
"private": True,
|
||||
"legacy": False,
|
||||
"role": "csk",
|
||||
"role_full": "key-signing",
|
||||
"dnskey_ttl": 3600,
|
||||
"flags": 257,
|
||||
}
|
||||
result.metadata = {
|
||||
"Algorithm": 13, # ECDSAP256SHA256
|
||||
"Length": 256,
|
||||
"Lifetime": 0,
|
||||
"KSK": "yes",
|
||||
"ZSK": "yes",
|
||||
}
|
||||
if with_state:
|
||||
result.metadata["GoalState"] = "omnipresent"
|
||||
result.metadata["DNSKEYState"] = "rumoured"
|
||||
result.metadata["KRRSIGState"] = "rumoured"
|
||||
result.metadata["ZRRSIGState"] = "rumoured"
|
||||
result.metadata["DSState"] = "hidden"
|
||||
|
||||
return result
|
||||
|
||||
def Ipub(self, config):
|
||||
ipub = timedelta(0)
|
||||
|
||||
if self.key.get_metadata("Predecessor", must_exist=False) != "undefined":
|
||||
# Ipub = Dprp + TTLkey
|
||||
ipub = (
|
||||
config["dnskey-ttl"]
|
||||
+ config["zone-propagation-delay"]
|
||||
+ config["publish-safety"]
|
||||
)
|
||||
|
||||
self.timing["Active"] = self.timing["Published"] + ipub
|
||||
|
||||
def IpubC(self, config):
|
||||
if not self.key.is_ksk():
|
||||
return
|
||||
|
||||
ttl1 = config["dnskey-ttl"] + config["publish-safety"]
|
||||
ttl2 = timedelta(0)
|
||||
|
||||
if self.key.get_metadata("Predecessor", must_exist=False) == "undefined":
|
||||
# If this is the first key, we also need to wait until the zone
|
||||
# signatures are omnipresent. Use max-zone-ttl instead of
|
||||
# dnskey-ttl, and no publish-safety (because we are looking at
|
||||
# signatures here, not the public key).
|
||||
ttl2 = config["max-zone-ttl"]
|
||||
|
||||
# IpubC = DprpC + TTLkey
|
||||
ipubc = config["zone-propagation-delay"] + max(ttl1, ttl2)
|
||||
|
||||
self.timing["PublishCDS"] = self.timing["Published"] + ipubc
|
||||
|
||||
if self.metadata["Lifetime"] != 0:
|
||||
self.timing["DeleteCDS"] = self.timing["PublishCDS"] + int(
|
||||
self.metadata["Lifetime"]
|
||||
)
|
||||
|
||||
def Iret(self, config):
|
||||
if self.metadata["Lifetime"] == 0:
|
||||
return
|
||||
|
||||
sign_delay = config["signatures-validity"] - config["signatures-refresh"]
|
||||
safety_interval = config["retire-safety"]
|
||||
|
||||
iretKSK = timedelta(0)
|
||||
iretZSK = timedelta(0)
|
||||
if self.key.is_ksk():
|
||||
# Iret = DprpP + TTLds
|
||||
iretKSK = (
|
||||
config["parent-propagation-delay"] + config["ds-ttl"] + safety_interval
|
||||
)
|
||||
if self.key.is_zsk():
|
||||
# Iret = Dsgn + Dprp + TTLsig
|
||||
iretZSK = (
|
||||
sign_delay
|
||||
+ config["zone-propagation-delay"]
|
||||
+ config["max-zone-ttl"]
|
||||
+ safety_interval
|
||||
)
|
||||
|
||||
self.timing["Removed"] = self.timing["Retired"] + max(iretKSK, iretZSK)
|
||||
|
||||
def set_expected_keytimes(self, config, offset=None, pregenerated=False):
|
||||
if self.key is None:
|
||||
raise ValueError("KeyProperties must be attached to a Key")
|
||||
|
||||
if self.properties["legacy"]:
|
||||
return
|
||||
|
||||
if offset is None:
|
||||
offset = self.properties["offset"]
|
||||
|
||||
self.timing["Generated"] = self.key.get_timing("Created")
|
||||
|
||||
self.timing["Published"] = self.timing["Generated"]
|
||||
if pregenerated:
|
||||
self.timing["Published"] = self.key.get_timing("Publish")
|
||||
self.timing["Published"] = self.timing["Published"] + offset
|
||||
self.Ipub(config)
|
||||
|
||||
# Set Retired timing metadata if key has lifetime.
|
||||
if self.metadata["Lifetime"] != 0:
|
||||
self.timing["Retired"] = self.timing["Active"] + int(
|
||||
self.metadata["Lifetime"]
|
||||
)
|
||||
|
||||
self.IpubC(config)
|
||||
self.Iret(config)
|
||||
|
||||
# Key state change times must exist, but since we cannot reliably tell
|
||||
# when named made the actual state change, we don't care what the
|
||||
# value is. Set it to None will verify that the metadata exists, but
|
||||
# without actual checking the value.
|
||||
self.timing["DNSKEYChange"] = None
|
||||
|
||||
if self.key.is_ksk():
|
||||
self.timing["DSChange"] = None
|
||||
self.timing["KRRSIGChange"] = None
|
||||
|
||||
if self.key.is_zsk():
|
||||
self.timing["ZRRSIGChange"] = None
|
||||
|
||||
|
||||
@total_ordering
|
||||
class KeyTimingMetadata:
|
||||
"""
|
||||
@@ -279,7 +117,6 @@ class Key:
|
||||
else:
|
||||
self.keydir = Path(keydir)
|
||||
self.path = str(self.keydir / name)
|
||||
self.privatefile = f"{self.path}.private"
|
||||
self.keyfile = f"{self.path}.key"
|
||||
self.statefile = f"{self.path}.state"
|
||||
self.tag = int(self.name[-5:])
|
||||
@@ -302,43 +139,21 @@ class Key:
|
||||
)
|
||||
return None
|
||||
|
||||
def get_metadata(
|
||||
self, metadata: str, file=None, comment=False, must_exist=True
|
||||
) -> str:
|
||||
if file is None:
|
||||
file = self.statefile
|
||||
def get_metadata(self, metadata: str, must_exist=True) -> str:
|
||||
value = "undefined"
|
||||
regex = rf"{metadata}:\s+(\S+).*"
|
||||
if comment:
|
||||
# The expected metadata is prefixed with a ';'.
|
||||
regex = rf";\s+{metadata}:\s+(\S+).*"
|
||||
with open(file, "r", encoding="utf-8") as fp:
|
||||
for line in fp:
|
||||
regex = rf"{metadata}:\s+(.*)"
|
||||
with open(self.statefile, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
match = re.match(regex, line)
|
||||
if match is not None:
|
||||
value = match.group(1)
|
||||
break
|
||||
if must_exist and value == "undefined":
|
||||
raise ValueError(
|
||||
f'metadata "{metadata}" for key "{self.name}" in file "{file}" undefined'
|
||||
'state metadata "{metadata}" for key "{self.name}" undefined'
|
||||
)
|
||||
return value
|
||||
|
||||
def ttl(self) -> int:
|
||||
with open(self.keyfile, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
if line.startswith(";"):
|
||||
continue
|
||||
return int(line.split()[1])
|
||||
return 0
|
||||
|
||||
def dnskey(self):
|
||||
with open(self.keyfile, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
if "DNSKEY" in line:
|
||||
return line.strip()
|
||||
return "undefined"
|
||||
|
||||
def is_ksk(self) -> bool:
|
||||
return self.get_metadata("KSK") == "yes"
|
||||
|
||||
@@ -372,7 +187,7 @@ class Key:
|
||||
dsfromkey_command = [
|
||||
os.environ.get("DSFROMKEY"),
|
||||
"-T",
|
||||
str(self.ttl()),
|
||||
"3600",
|
||||
"-a",
|
||||
alg,
|
||||
"-C",
|
||||
@@ -401,152 +216,6 @@ class Key:
|
||||
|
||||
return digest_fromfile == digest_fromwire
|
||||
|
||||
def has_metadata(self, key, metadata):
|
||||
# If 'key' exists in 'metadata' then it must also exist in the state
|
||||
# meta data. Otherwise, it must not exist in the state meta data.
|
||||
if key in metadata:
|
||||
return self.get_metadata(key) != "undefined"
|
||||
|
||||
value = self.get_metadata(key, must_exist=False)
|
||||
if value != "undefined":
|
||||
isctest.log.debug(f"{self.name} {key} METADATA UNEXPECTED: {value}")
|
||||
return value == "undefined"
|
||||
|
||||
def match_metadata(self, key, metadata):
|
||||
# If 'key' exists in 'metadata' then it must match the value in the
|
||||
# state meta data. Otherwise, it must also not exist in the state meta
|
||||
# data.
|
||||
if key in metadata:
|
||||
value = self.get_metadata(key)
|
||||
if value != f"{metadata[key]}":
|
||||
isctest.log.debug(
|
||||
f"{self.name} {key} METADATA MISMATCH: {value} - {metadata[key]}"
|
||||
)
|
||||
return value == f"{metadata[key]}"
|
||||
|
||||
value = self.get_metadata(key, must_exist=False)
|
||||
if value != "undefined":
|
||||
isctest.log.debug(f"{self.name} {key} METADATA UNEXPECTED: {value}")
|
||||
return value == "undefined"
|
||||
|
||||
def match_timing(self, key, timing, file, comment=False):
|
||||
# If 'key' exists in 'timing' then it must match the value in the
|
||||
# state timing data. Otherwise, it must also not exist in the state timing
|
||||
# data.
|
||||
if key in timing:
|
||||
value = self.get_metadata(key, file=file, comment=comment)
|
||||
if value != str(timing[key]):
|
||||
isctest.log.debug(
|
||||
f"{self.name} {key} TIMING MISMATCH: {value} - {timing[key]}"
|
||||
)
|
||||
return value == str(timing[key])
|
||||
|
||||
value = self.get_metadata(key, file=file, comment=comment, must_exist=False)
|
||||
if value != "undefined":
|
||||
isctest.log.debug(f"{self.name} {key} TIMING UNEXPECTED: {value}")
|
||||
return value == "undefined"
|
||||
|
||||
def match_properties(self, zone, properties):
|
||||
# Check the key with given properties.
|
||||
if not properties.properties["expect"]:
|
||||
return False
|
||||
|
||||
# Check file existence.
|
||||
# Noop. If file is missing then the get_metadata calls will fail.
|
||||
|
||||
# Check the public key file.
|
||||
role = properties.properties["role_full"]
|
||||
comment = f"This is a {role} key, keyid {self.tag}, for {zone}."
|
||||
if not isctest.check.file_contents_contain(self.keyfile, comment):
|
||||
isctest.log.debug(f"{self.name} COMMENT MISMATCH: expected '{comment}'")
|
||||
return False
|
||||
|
||||
ttl = properties.properties["dnskey_ttl"]
|
||||
flags = properties.properties["flags"]
|
||||
alg = properties.metadata["Algorithm"]
|
||||
dnskey = f"{zone}. {ttl} IN DNSKEY {flags} 3 {alg}"
|
||||
if not isctest.check.file_contents_contain(self.keyfile, dnskey):
|
||||
isctest.log.debug(f"{self.name} DNSKEY MISMATCH: expected '{dnskey}'")
|
||||
return False
|
||||
|
||||
# Now check the private key file.
|
||||
if properties.properties["private"]:
|
||||
# Retrieve creation date.
|
||||
created = self.get_metadata("Generated")
|
||||
|
||||
pval = self.get_metadata("Created", file=self.privatefile)
|
||||
if pval != created:
|
||||
isctest.log.debug(
|
||||
f"{self.name} Created METADATA MISMATCH: {pval} - {created}"
|
||||
)
|
||||
return False
|
||||
pval = self.get_metadata("Private-key-format", file=self.privatefile)
|
||||
if pval != "v1.3":
|
||||
isctest.log.debug(
|
||||
f"{self.name} Private-key-format METADATA MISMATCH: {pval} - v1.3"
|
||||
)
|
||||
return False
|
||||
pval = self.get_metadata("Algorithm", file=self.privatefile)
|
||||
if pval != f"{alg}":
|
||||
isctest.log.debug(
|
||||
f"{self.name} Algorithm METADATA MISMATCH: {pval} - {alg}"
|
||||
)
|
||||
return False
|
||||
|
||||
# Now check the key state file.
|
||||
if properties.properties["legacy"]:
|
||||
return True
|
||||
|
||||
comment = f"This is the state of key {self.tag}, for {zone}."
|
||||
if not isctest.check.file_contents_contain(self.statefile, comment):
|
||||
isctest.log.debug(f"{self.name} COMMENT MISMATCH: expected '{comment}'")
|
||||
return False
|
||||
|
||||
attributes = [
|
||||
"Lifetime",
|
||||
"Algorithm",
|
||||
"Length",
|
||||
"KSK",
|
||||
"ZSK",
|
||||
"GoalState",
|
||||
"DNSKEYState",
|
||||
"KRRSIGState",
|
||||
"ZRRSIGState",
|
||||
"DSState",
|
||||
]
|
||||
for key in attributes:
|
||||
if not self.match_metadata(key, properties.metadata):
|
||||
return False
|
||||
|
||||
# A match is found.
|
||||
return True
|
||||
|
||||
def match_timingmetadata(self, timings, file=None, comment=False):
|
||||
if file is None:
|
||||
file = self.statefile
|
||||
|
||||
attributes = [
|
||||
"Generated",
|
||||
"Created",
|
||||
"Published",
|
||||
"Publish",
|
||||
"PublishCDS",
|
||||
"SyncPublish",
|
||||
"Active",
|
||||
"Activate",
|
||||
"Retired",
|
||||
"Inactive",
|
||||
"Revoked",
|
||||
"Removed",
|
||||
"Delete",
|
||||
]
|
||||
for key in attributes:
|
||||
if not self.match_timing(key, timings, file, comment=comment):
|
||||
isctest.log.debug(f"{self.name} TIMING METADATA MISMATCH: {key}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __lt__(self, other: "Key"):
|
||||
return self.name < other.name
|
||||
|
||||
@@ -557,14 +226,14 @@ class Key:
|
||||
return self.path
|
||||
|
||||
|
||||
def check_zone_is_signed(server, zone, tsig=None):
|
||||
def check_zone_is_signed(server, zone):
|
||||
addr = server.ip
|
||||
fqdn = f"{zone}."
|
||||
|
||||
# wait until zone is fully signed
|
||||
signed = False
|
||||
for _ in range(10):
|
||||
response = _query(server, fqdn, dns.rdatatype.NSEC, tsig=tsig)
|
||||
response = _query(server, fqdn, dns.rdatatype.NSEC)
|
||||
if not isinstance(response, dns.message.Message):
|
||||
isctest.log.debug(f"no response for {fqdn} NSEC from {addr}")
|
||||
elif response.rcode() != dns.rcode.NOERROR:
|
||||
@@ -608,111 +277,13 @@ def check_zone_is_signed(server, zone, tsig=None):
|
||||
assert signed
|
||||
|
||||
|
||||
def check_keys(zone, keys, expected):
|
||||
# Checks keys for a configured zone. This verifies:
|
||||
# 1. The expected number of keys exist in 'keys'.
|
||||
# 2. The keys match the expected properties.
|
||||
|
||||
def _check_keys():
|
||||
# check number of keys matches expected.
|
||||
if len(keys) != len(expected):
|
||||
return False
|
||||
|
||||
if len(keys) == 0:
|
||||
return True
|
||||
|
||||
for expect in expected:
|
||||
expect.key = None
|
||||
|
||||
for key in keys:
|
||||
found = False
|
||||
i = 0
|
||||
while not found and i < len(expected):
|
||||
if expected[i].key is None:
|
||||
found = key.match_properties(zone, expected[i])
|
||||
if found:
|
||||
key.external = expected[i].properties["legacy"]
|
||||
expected[i].key = key
|
||||
i += 1
|
||||
if not found:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
isctest.run.retry_with_timeout(_check_keys, timeout=10)
|
||||
|
||||
|
||||
def check_keytimes(keys, expected):
|
||||
# Check the key timing metadata for all keys in 'keys'.
|
||||
assert len(keys) == len(expected)
|
||||
|
||||
if len(keys) == 0:
|
||||
return
|
||||
|
||||
for key in keys:
|
||||
for expect in expected:
|
||||
if expect.properties["legacy"]:
|
||||
continue
|
||||
|
||||
if not key is expect.key:
|
||||
continue
|
||||
|
||||
synonyms = {}
|
||||
if "Generated" in expect.timing:
|
||||
synonyms["Created"] = expect.timing["Generated"]
|
||||
if "Published" in expect.timing:
|
||||
synonyms["Publish"] = expect.timing["Published"]
|
||||
if "PublishCDS" in expect.timing:
|
||||
synonyms["SyncPublish"] = expect.timing["PublishCDS"]
|
||||
if "Active" in expect.timing:
|
||||
synonyms["Activate"] = expect.timing["Active"]
|
||||
if "Retired" in expect.timing:
|
||||
synonyms["Inactive"] = expect.timing["Retired"]
|
||||
if "DeleteCDS" in expect.timing:
|
||||
synonyms["SyncDelete"] = expect.timing["DeleteCDS"]
|
||||
if "Revoked" in expect.timing:
|
||||
synonyms["Revoked"] = expect.timing["Revoked"]
|
||||
if "Removed" in expect.timing:
|
||||
synonyms["Delete"] = expect.timing["Removed"]
|
||||
|
||||
assert key.match_timingmetadata(synonyms, file=key.keyfile, comment=True)
|
||||
if expect.properties["private"]:
|
||||
assert key.match_timingmetadata(synonyms, file=key.privatefile)
|
||||
if not expect.properties["legacy"]:
|
||||
assert key.match_timingmetadata(expect.timing)
|
||||
|
||||
state_changes = [
|
||||
"DNSKEYChange",
|
||||
"KRRSIGChange",
|
||||
"ZRRSIGChange",
|
||||
"DSChange",
|
||||
]
|
||||
for change in state_changes:
|
||||
assert key.has_metadata(change, expect.timing)
|
||||
|
||||
|
||||
def check_keyrelationships(keys, expected):
|
||||
# Check the key relationships (Successor and Predecessor metadata).
|
||||
for key in keys:
|
||||
for expect in expected:
|
||||
if expect.properties["legacy"]:
|
||||
continue
|
||||
|
||||
if not key is expect.key:
|
||||
continue
|
||||
|
||||
relationship_status = ["Predecessor", "Successor"]
|
||||
for status in relationship_status:
|
||||
assert key.match_metadata(status, expect.metadata)
|
||||
|
||||
|
||||
def check_dnssec_verify(server, zone, tsig=None):
|
||||
def check_dnssec_verify(server, zone):
|
||||
# Check if zone if DNSSEC valid with dnssec-verify.
|
||||
fqdn = f"{zone}."
|
||||
|
||||
verified = False
|
||||
for _ in range(10):
|
||||
transfer = _query(server, fqdn, dns.rdatatype.AXFR, tsig=tsig)
|
||||
transfer = _query(server, fqdn, dns.rdatatype.AXFR)
|
||||
if not isinstance(transfer, dns.message.Message):
|
||||
isctest.log.debug(f"no response for {fqdn} AXFR from {server.ip}")
|
||||
elif transfer.rcode() != dns.rcode.NOERROR:
|
||||
@@ -844,9 +415,9 @@ def _check_dnskeys(dnskeys, keys, cdnskey=False):
|
||||
delete_md = f"Sync{delete_md}"
|
||||
|
||||
for key in keys:
|
||||
publish = key.get_timing(publish_md, must_exist=False)
|
||||
publish = key.get_timing(publish_md)
|
||||
delete = key.get_timing(delete_md, must_exist=False)
|
||||
published = publish is not None and now >= publish
|
||||
published = now >= publish
|
||||
removed = delete is not None and delete <= now
|
||||
|
||||
if not published or removed:
|
||||
@@ -931,8 +502,8 @@ def check_cds(rrset, keys):
|
||||
assert numcds == len(cdss)
|
||||
|
||||
|
||||
def _query_rrset(server, fqdn, qtype, tsig=None):
|
||||
response = _query(server, fqdn, qtype, tsig=tsig)
|
||||
def _query_rrset(server, fqdn, qtype):
|
||||
response = _query(server, fqdn, qtype)
|
||||
assert response.rcode() == dns.rcode.NOERROR
|
||||
|
||||
rrs = []
|
||||
@@ -952,43 +523,46 @@ def _query_rrset(server, fqdn, qtype, tsig=None):
|
||||
return rrs, rrsigs
|
||||
|
||||
|
||||
def check_apex(server, zone, ksks, zsks, tsig=None):
|
||||
def check_apex(server, zone, ksks, zsks):
|
||||
# Test the apex of a zone. This checks that the SOA and DNSKEY RRsets
|
||||
# are signed correctly and with the appropriate keys.
|
||||
fqdn = f"{zone}."
|
||||
|
||||
# test dnskey query
|
||||
dnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.DNSKEY, tsig=tsig)
|
||||
dnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.DNSKEY)
|
||||
assert len(dnskeys) > 0
|
||||
check_dnskeys(dnskeys, ksks, zsks)
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.DNSKEY, fqdn, ksks, zsks)
|
||||
|
||||
# test soa query
|
||||
soa, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.SOA, tsig=tsig)
|
||||
soa, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.SOA)
|
||||
assert len(soa) == 1
|
||||
assert f"{zone}. {DEFAULT_TTL} IN SOA" in soa[0].to_text()
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.SOA, fqdn, ksks, zsks)
|
||||
|
||||
# test cdnskey query
|
||||
cdnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDNSKEY, tsig=tsig)
|
||||
cdnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDNSKEY)
|
||||
check_dnskeys(cdnskeys, ksks, zsks, cdnskey=True)
|
||||
if len(cdnskeys) > 0:
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.CDNSKEY, fqdn, ksks, zsks)
|
||||
|
||||
# test cds query
|
||||
cds, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDS, tsig=tsig)
|
||||
cds, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.CDS)
|
||||
check_cds(cds, ksks)
|
||||
if len(cds) > 0:
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, dns.rdatatype.CDS, fqdn, ksks, zsks)
|
||||
|
||||
|
||||
def check_subdomain(server, zone, ksks, zsks, tsig=None):
|
||||
def check_subdomain(server, zone, ksks, zsks):
|
||||
# Test an RRset below the apex and verify it is signed correctly.
|
||||
fqdn = f"{zone}."
|
||||
qname = f"a.{zone}."
|
||||
qtype = dns.rdatatype.A
|
||||
response = _query(server, qname, qtype, tsig=tsig)
|
||||
response = _query(server, qname, qtype)
|
||||
assert response.rcode() == dns.rcode.NOERROR
|
||||
|
||||
match = f"{qname} {DEFAULT_TTL} IN A 10.0.0.1"
|
||||
@@ -1001,180 +575,5 @@ def check_subdomain(server, zone, ksks, zsks, tsig=None):
|
||||
else:
|
||||
assert match in rrset.to_text()
|
||||
|
||||
assert len(rrsigs) > 0
|
||||
check_signatures(rrsigs, qtype, fqdn, ksks, zsks)
|
||||
|
||||
|
||||
def check_update_is_signed(server, fqdn, qname, qtype, rdata, ksks, zsks, tsig=None):
|
||||
# Test an RRset below the apex and verify it is updated and signed correctly.
|
||||
response = _query(server, qname, qtype, tsig=tsig)
|
||||
|
||||
if response.rcode() != dns.rcode.NOERROR:
|
||||
return False
|
||||
|
||||
rrtype = dns.rdatatype.to_text(qtype)
|
||||
match = f"{qname} {DEFAULT_TTL} IN {rrtype} {rdata}"
|
||||
rrsigs = []
|
||||
for rrset in response.answer:
|
||||
if rrset.match(
|
||||
dns.name.from_text(qname), dns.rdataclass.IN, dns.rdatatype.RRSIG, qtype
|
||||
):
|
||||
rrsigs.append(rrset)
|
||||
elif not match in rrset.to_text():
|
||||
return False
|
||||
|
||||
if len(rrsigs) == 0:
|
||||
return False
|
||||
|
||||
# Zone is updated, ready to verify the signatures.
|
||||
check_signatures(rrsigs, qtype, fqdn, ksks, zsks)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_next_key_event(server, zone, next_event):
|
||||
if next_event is None:
|
||||
# No next key event check.
|
||||
return True
|
||||
|
||||
val = int(next_event.total_seconds())
|
||||
if val == 3600:
|
||||
waitfor = rf".*zone {zone}.*: next key event in (.*) seconds"
|
||||
else:
|
||||
# Don't want default loadkeys interval.
|
||||
waitfor = rf".*zone {zone}.*: next key event in (?!3600$)(.*) seconds"
|
||||
|
||||
with server.watch_log_from_start() as watcher:
|
||||
watcher.wait_for_line(re.compile(waitfor))
|
||||
|
||||
next_found = False
|
||||
minval = val - NEXT_KEY_EVENT_THRESHOLD
|
||||
maxval = val + NEXT_KEY_EVENT_THRESHOLD
|
||||
with open(f"{server.identifier}/named.run", "r", encoding="utf-8") as fp:
|
||||
for line in fp:
|
||||
match = re.match(waitfor, line)
|
||||
if match is not None:
|
||||
nextval = int(match.group(1))
|
||||
if minval <= nextval <= maxval:
|
||||
next_found = True
|
||||
break
|
||||
|
||||
isctest.log.debug(
|
||||
f"check next key event: expected {val} in: {line.strip()}"
|
||||
)
|
||||
|
||||
return next_found
|
||||
|
||||
|
||||
def keydir_to_keylist(
|
||||
zone: str, keydir: Optional[str] = None, in_use: Optional[bool] = False
|
||||
) -> List[Key]:
|
||||
# Retrieve all keys from the key files in a directory. If 'zone' is None,
|
||||
# retrieve all keys in the directory, otherwise only those matching the
|
||||
# zone name. If 'keydir' is None, search the current directory.
|
||||
if zone is None:
|
||||
zone = ""
|
||||
|
||||
all_keys = []
|
||||
if keydir is None:
|
||||
regex = rf"(K{zone}\.\+.*\+.*)\.key"
|
||||
for filename in glob.glob(f"K{zone}.+*+*.key"):
|
||||
match = re.match(regex, filename)
|
||||
if match is not None:
|
||||
all_keys.append(Key(match.group(1)))
|
||||
else:
|
||||
regex = rf"{keydir}/(K{zone}\.\+.*\+.*)\.key"
|
||||
for filename in glob.glob(f"{keydir}/K{zone}.+*+*.key"):
|
||||
match = re.match(regex, filename)
|
||||
if match is not None:
|
||||
all_keys.append(Key(match.group(1), keydir))
|
||||
|
||||
states = ["GoalState", "DNSKEYState", "KRRSIGState", "ZRRSIGState", "DSState"]
|
||||
|
||||
def used(kk):
|
||||
if not in_use:
|
||||
return True
|
||||
|
||||
for state in states:
|
||||
val = kk.get_metadata(state, must_exist=False)
|
||||
if val not in ["undefined", "hidden"]:
|
||||
isctest.log.debug(f"key {kk} in use")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
return [k for k in all_keys if used(k)]
|
||||
|
||||
|
||||
def keystr_to_keylist(keystr: str, keydir: Optional[str] = None) -> List[Key]:
|
||||
return [Key(name, keydir) for name in keystr.split()]
|
||||
|
||||
|
||||
def policy_to_properties(ttl, keys: List[str]) -> List[KeyProperties]:
|
||||
# Get the policies from a list of specially formatted strings.
|
||||
# The splitted line should result in the following items:
|
||||
# line[0]: Role
|
||||
# line[1]: Lifetime
|
||||
# line[2]: Algorithm
|
||||
# line[3]: Length
|
||||
# Then, optional data for specific tests may follow:
|
||||
# - "goal", "dnskey", "krrsig", "zrrsig", "ds", followed by a value,
|
||||
# sets the given state to the specific value
|
||||
# - "offset", an offset for testing key rollover timings
|
||||
proplist = []
|
||||
count = 0
|
||||
for key in keys:
|
||||
count += 1
|
||||
line = key.split()
|
||||
keyprop = KeyProperties(f"KEY{count}", {}, {}, {})
|
||||
keyprop.properties["expect"] = True
|
||||
keyprop.properties["private"] = True
|
||||
keyprop.properties["legacy"] = False
|
||||
keyprop.properties["offset"] = timedelta(0)
|
||||
keyprop.properties["role"] = line[0]
|
||||
if line[0] == "zsk":
|
||||
keyprop.properties["role_full"] = "zone-signing"
|
||||
keyprop.properties["flags"] = 256
|
||||
keyprop.metadata["ZSK"] = "yes"
|
||||
keyprop.metadata["KSK"] = "no"
|
||||
else:
|
||||
keyprop.properties["role_full"] = "key-signing"
|
||||
keyprop.properties["flags"] = 257
|
||||
keyprop.metadata["ZSK"] = "yes" if line[0] == "csk" else "no"
|
||||
keyprop.metadata["KSK"] = "yes"
|
||||
|
||||
keyprop.properties["dnskey_ttl"] = ttl
|
||||
keyprop.metadata["Algorithm"] = line[2]
|
||||
keyprop.metadata["Length"] = line[3]
|
||||
keyprop.metadata["Lifetime"] = 0
|
||||
if line[1] != "unlimited":
|
||||
keyprop.metadata["Lifetime"] = int(line[1])
|
||||
|
||||
if len(line) > 4:
|
||||
i = 4
|
||||
while i < len(line):
|
||||
if line[i].startswith("goal:"):
|
||||
keyval = line[i].split(":")
|
||||
keyprop.metadata["GoalState"] = keyval[1]
|
||||
elif line[i].startswith("dnskey:"):
|
||||
keyval = line[i].split(":")
|
||||
keyprop.metadata["DNSKEYState"] = keyval[1]
|
||||
elif line[i].startswith("krrsig:"):
|
||||
keyval = line[i].split(":")
|
||||
keyprop.metadata["KRRSIGState"] = keyval[1]
|
||||
elif line[i].startswith("zrrsig:"):
|
||||
keyval = line[i].split(":")
|
||||
keyprop.metadata["ZRRSIGState"] = keyval[1]
|
||||
elif line[i].startswith("ds:"):
|
||||
keyval = line[i].split(":")
|
||||
keyprop.metadata["DSState"] = keyval[1]
|
||||
elif line[i].startswith("offset:"):
|
||||
keyval = line[i].split(":")
|
||||
keyprop.properties["offset"] = timedelta(seconds=int(keyval[1]))
|
||||
else:
|
||||
assert False, f"undefined optional data {line[i]}"
|
||||
|
||||
i += 1
|
||||
|
||||
proplist.append(keyprop)
|
||||
|
||||
return proplist
|
||||
|
||||
@@ -130,7 +130,7 @@ $KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone >keygen.out.$zone.2 2>&1
|
||||
zone="multisigner-model2.kasp"
|
||||
echo_i "setting up zone: $zone"
|
||||
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.2)
|
||||
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zone -M 32768:65535 2>keygen.out.$zone.2)
|
||||
cat "${KSK}.key" | grep -v ";.*" >>"${zone}.db"
|
||||
cat "${ZSK}.key" | grep -v ";.*" >>"${zone}.db"
|
||||
# Import the ZSK sets of the other providers into their DNSKEY RRset.
|
||||
@@ -350,9 +350,10 @@ setup step2.enable-dnssec.autosign
|
||||
TpubN="now-900s"
|
||||
# RRSIG TTL: 12 hour (43200 seconds)
|
||||
# zone-propagation-delay: 5 minutes (300 seconds)
|
||||
# retire-safety: 20 minutes (1200 seconds)
|
||||
# Already passed time: -900 seconds
|
||||
# Total: 42600 seconds
|
||||
TsbmN="now+42600s"
|
||||
# Total: 43800 seconds
|
||||
TsbmN="now+43800s"
|
||||
keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
|
||||
CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2>keygen.out.$zone.1)
|
||||
$SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1
|
||||
@@ -364,10 +365,10 @@ $SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $i
|
||||
# Step 3:
|
||||
# The zone signatures have been published long enough to become OMNIPRESENT.
|
||||
setup step3.enable-dnssec.autosign
|
||||
# Passed time since publications: 42600 + 900 = 43500 seconds.
|
||||
TpubN="now-43500s"
|
||||
# Passed time since publications: 43800 + 900 = 44700 seconds.
|
||||
TpubN="now-44700s"
|
||||
# The key is secure for using in chain of trust when the DNSKEY is OMNIPRESENT.
|
||||
TcotN="now-42600s"
|
||||
TcotN="now-43800s"
|
||||
# We can submit the DS now.
|
||||
TsbmN="now"
|
||||
keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
|
||||
|
||||
@@ -127,9 +127,9 @@ setup step2.algorithm-roll.kasp
|
||||
# The time passed since the new algorithm keys have been introduced is 3 hours.
|
||||
TactN="now-3h"
|
||||
TpubN1="now-3h"
|
||||
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp =
|
||||
# now - 3h + 6h + 1h = now + 4h
|
||||
TsbmN1="now+4h"
|
||||
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp + publish-safety =
|
||||
# now - 3h + 6h + 1h + 1h = now + 5h
|
||||
TsbmN1="now+5h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I now"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -156,11 +156,11 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# Step 3:
|
||||
# The zone signatures are also OMNIPRESENT.
|
||||
setup step3.algorithm-roll.kasp
|
||||
# The time passed since the new algorithm keys have been introduced is 7 hours.
|
||||
TactN="now-7h"
|
||||
TretN="now-3h"
|
||||
TpubN1="now-7h"
|
||||
TsbmN1="now"
|
||||
# The time passed since the new algorithm keys have been introduced is 9 hours.
|
||||
TactN="now-9h"
|
||||
TretN="now-6h"
|
||||
TpubN1="now-9h"
|
||||
TsbmN1="now-1h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -188,11 +188,11 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# The DS is swapped and can become OMNIPRESENT.
|
||||
setup step4.algorithm-roll.kasp
|
||||
# The time passed since the DS has been swapped is 29 hours.
|
||||
TactN="now-36h"
|
||||
TretN="now-33h"
|
||||
TpubN1="now-36h"
|
||||
TsbmN1="now-29h"
|
||||
TactN1="now-27h"
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TpubN1="now-38h"
|
||||
TsbmN1="now-30h"
|
||||
TactN1="now-29h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -220,12 +220,12 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# The DNSKEY is removed long enough to be HIDDEN.
|
||||
setup step5.algorithm-roll.kasp
|
||||
# The time passed since the DNSKEY has been removed is 2 hours.
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TactN="now-40h"
|
||||
TretN="now-37h"
|
||||
TremN="now-2h"
|
||||
TpubN1="now-38h"
|
||||
TsbmN1="now-31h"
|
||||
TactN1="now-29h"
|
||||
TpubN1="now-40h"
|
||||
TsbmN1="now-32h"
|
||||
TactN1="now-31h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -253,13 +253,13 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# The RRSIGs have been removed long enough to be HIDDEN.
|
||||
setup step6.algorithm-roll.kasp
|
||||
# Additional time passed: 7h.
|
||||
TactN="now-45h"
|
||||
TretN="now-42h"
|
||||
TactN="now-47h"
|
||||
TretN="now-44h"
|
||||
TremN="now-7h"
|
||||
TpubN1="now-45h"
|
||||
TsbmN1="now-38h"
|
||||
TactN1="now-36h"
|
||||
TdeaN="now-7h"
|
||||
TpubN1="now-47h"
|
||||
TsbmN1="now-39h"
|
||||
TactN1="now-38h"
|
||||
TdeaN="now-9h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -324,11 +324,11 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# Step 3:
|
||||
# The zone signatures are also OMNIPRESENT.
|
||||
setup step3.csk-algorithm-roll.kasp
|
||||
# The time passed since the new algorithm keys have been introduced is 7 hours.
|
||||
TactN="now-7h"
|
||||
TretN="now-3h"
|
||||
TpubN1="now-7h"
|
||||
TactN1="now-3h"
|
||||
# The time passed since the new algorithm keys have been introduced is 9 hours.
|
||||
TactN="now-9h"
|
||||
TretN="now-6h"
|
||||
TpubN1="now-9h"
|
||||
TactN1="now-6h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
|
||||
@@ -347,10 +347,10 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# The DS is swapped and can become OMNIPRESENT.
|
||||
setup step4.csk-algorithm-roll.kasp
|
||||
# The time passed since the DS has been swapped is 29 hours.
|
||||
TactN="now-36h"
|
||||
TretN="now-33h"
|
||||
TpubN1="now-36h"
|
||||
TactN1="now-33h"
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TpubN1="now-38h"
|
||||
TactN1="now-35h"
|
||||
TsubN1="now-29h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
@@ -370,11 +370,11 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# The DNSKEY is removed long enough to be HIDDEN.
|
||||
setup step5.csk-algorithm-roll.kasp
|
||||
# The time passed since the DNSKEY has been removed is 2 hours.
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TactN="now-40h"
|
||||
TretN="now-37h"
|
||||
TremN="now-2h"
|
||||
TpubN1="now-38h"
|
||||
TactN1="now-35h"
|
||||
TpubN1="now-40h"
|
||||
TactN1="now-37h"
|
||||
TsubN1="now-31h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
@@ -394,12 +394,12 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# The RRSIGs have been removed long enough to be HIDDEN.
|
||||
setup step6.csk-algorithm-roll.kasp
|
||||
# Additional time passed: 7h.
|
||||
TactN="now-45h"
|
||||
TretN="now-42h"
|
||||
TactN="now-47h"
|
||||
TretN="now-44h"
|
||||
TdeaN="now-9h"
|
||||
TremN="now-7h"
|
||||
TpubN1="now-45h"
|
||||
TactN1="now-42h"
|
||||
TpubN1="now-47h"
|
||||
TactN1="now-44h"
|
||||
TsubN1="now-38h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 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.
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
if test -n "$PYTHON"; then
|
||||
if $PYTHON -c "from dns.update import UpdateMessage" 2>/dev/null; then
|
||||
:
|
||||
else
|
||||
echo_i "This test requires the dnspython >= 2.0.0 module." >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo_i "This test requires Python and the dnspython module." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
+588
-125
@@ -54,6 +54,178 @@ next_key_event_threshold=100
|
||||
# Tests #
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# dnssec-keygen
|
||||
#
|
||||
set_zone "kasp"
|
||||
set_policy "kasp" "4" "200"
|
||||
set_server "keys" "10.53.0.1"
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-keygen -k' (configured policy) creates valid files ($n)"
|
||||
ret=0
|
||||
$KEYGEN -K keys -k "$POLICY" -l kasp.conf "$ZONE" >"keygen.out.$POLICY.test$n" 2>/dev/null || ret=1
|
||||
lines=$(wc -l <"keygen.out.$POLICY.test$n")
|
||||
test "$lines" -eq $NUM_KEYS || log_error "wrong number of keys created for policy kasp: $lines"
|
||||
# Temporarily don't log errors because we are searching multiple files.
|
||||
disable_logerror
|
||||
|
||||
# Key properties.
|
||||
set_keyrole "KEY1" "csk"
|
||||
set_keylifetime "KEY1" "31536000"
|
||||
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "yes"
|
||||
|
||||
set_keyrole "KEY2" "ksk"
|
||||
set_keylifetime "KEY2" "31536000"
|
||||
set_keyalgorithm "KEY2" "8" "RSASHA256" "2048"
|
||||
set_keysigning "KEY2" "yes"
|
||||
set_zonesigning "KEY2" "no"
|
||||
|
||||
set_keyrole "KEY3" "zsk"
|
||||
set_keylifetime "KEY3" "2592000"
|
||||
set_keyalgorithm "KEY3" "8" "RSASHA256" "2048"
|
||||
set_keysigning "KEY3" "no"
|
||||
set_zonesigning "KEY3" "yes"
|
||||
|
||||
set_keyrole "KEY4" "zsk"
|
||||
set_keylifetime "KEY4" "16070400"
|
||||
set_keyalgorithm "KEY4" "8" "RSASHA256" "3072"
|
||||
set_keysigning "KEY4" "no"
|
||||
set_zonesigning "KEY4" "yes"
|
||||
|
||||
lines=$(get_keyids "$DIR" "$ZONE" | wc -l)
|
||||
test "$lines" -eq $NUM_KEYS || log_error "bad number of key ids"
|
||||
status=$((status + ret))
|
||||
|
||||
ids=$(get_keyids "$DIR" "$ZONE")
|
||||
for id in $ids; do
|
||||
# There are four key files with the same algorithm.
|
||||
# Check them until a match is found.
|
||||
ret=0 && check_key "KEY1" "$id"
|
||||
test "$ret" -eq 0 && continue
|
||||
|
||||
ret=0 && check_key "KEY2" "$id"
|
||||
test "$ret" -eq 0 && continue
|
||||
|
||||
ret=0 && check_key "KEY3" "$id"
|
||||
test "$ret" -eq 0 && continue
|
||||
|
||||
ret=0 && check_key "KEY4" "$id"
|
||||
|
||||
# If ret is still non-zero, non of the files matched.
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
done
|
||||
# Turn error logs on again.
|
||||
enable_logerror
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-keygen -k' (default policy) creates valid files ($n)"
|
||||
ret=0
|
||||
set_zone "kasp"
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "." "10.53.0.1"
|
||||
# Key properties.
|
||||
key_clear "KEY1"
|
||||
set_keyrole "KEY1" "csk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
|
||||
set_keysigning "KEY1" "yes"
|
||||
set_zonesigning "KEY1" "yes"
|
||||
|
||||
key_clear "KEY2"
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
$KEYGEN -G -k "$POLICY" "$ZONE" >"keygen.out.$POLICY.test$n" 2>/dev/null || ret=1
|
||||
lines=$(wc -l <"keygen.out.$POLICY.test$n")
|
||||
test "$lines" -eq $NUM_KEYS || log_error "wrong number of keys created for policy default: $lines"
|
||||
# Temporarily adjust max search depth for this test
|
||||
MAXDEPTH=1
|
||||
ids=$(get_keyids "$DIR" "$ZONE")
|
||||
MAXDEPTH=3
|
||||
echo_i "found in dir $DIR for zone $ZONE the following keytags: $ids"
|
||||
for id in $ids; do
|
||||
check_key "KEY1" "$id"
|
||||
test "$ret" -eq 0 && key_save KEY1
|
||||
check_keytimes
|
||||
done
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# dnssec-settime
|
||||
#
|
||||
|
||||
# These test builds upon the latest created key with dnssec-keygen and uses the
|
||||
# environment variables BASE_FILE, KEY_FILE, PRIVATE_FILE and STATE_FILE.
|
||||
CMP_FILE="${BASE_FILE}.cmp"
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-settime' by default does not edit key state file ($n)"
|
||||
ret=0
|
||||
cp "$STATE_FILE" "$CMP_FILE"
|
||||
$SETTIME -P +3600 "$BASE_FILE" >/dev/null || log_error "settime failed"
|
||||
grep "; Publish: " "$KEY_FILE" >/dev/null || log_error "mismatch published in $KEY_FILE"
|
||||
grep "Publish: " "$PRIVATE_FILE" >/dev/null || log_error "mismatch published in $PRIVATE_FILE"
|
||||
diff "$CMP_FILE" "$STATE_FILE" || log_error "unexpected file change in $STATE_FILE"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-settime -s' also sets publish time metadata and states in key state file ($n)"
|
||||
ret=0
|
||||
cp "$STATE_FILE" "$CMP_FILE"
|
||||
now=$(date +%Y%m%d%H%M%S)
|
||||
$SETTIME -s -P "$now" -g "omnipresent" -k "rumoured" "$now" -z "omnipresent" "$now" -r "rumoured" "$now" -d "hidden" "$now" "$BASE_FILE" >/dev/null || log_error "settime failed"
|
||||
set_keystate "KEY1" "GOAL" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY1" "STATE_ZRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_DS" "hidden"
|
||||
check_key "KEY1" "$id"
|
||||
test "$ret" -eq 0 && key_save KEY1
|
||||
set_keytime "KEY1" "PUBLISHED" "${now}"
|
||||
check_keytimes
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-settime -s' also unsets publish time metadata and states in key state file ($n)"
|
||||
ret=0
|
||||
cp "$STATE_FILE" "$CMP_FILE"
|
||||
$SETTIME -s -P "none" -g "none" -k "none" "$now" -z "none" "$now" -r "none" "$now" -d "none" "$now" "$BASE_FILE" >/dev/null || log_error "settime failed"
|
||||
set_keystate "KEY1" "GOAL" "none"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "none"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "none"
|
||||
set_keystate "KEY1" "STATE_ZRRSIG" "none"
|
||||
set_keystate "KEY1" "STATE_DS" "none"
|
||||
check_key "KEY1" "$id"
|
||||
test "$ret" -eq 0 && key_save KEY1
|
||||
set_keytime "KEY1" "PUBLISHED" "none"
|
||||
check_keytimes
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that 'dnssec-settime -s' also sets active time metadata and states in key state file (uppercase) ($n)"
|
||||
ret=0
|
||||
cp "$STATE_FILE" "$CMP_FILE"
|
||||
now=$(date +%Y%m%d%H%M%S)
|
||||
$SETTIME -s -A "$now" -g "HIDDEN" -k "UNRETENTIVE" "$now" -z "UNRETENTIVE" "$now" -r "OMNIPRESENT" "$now" -d "OMNIPRESENT" "$now" "$BASE_FILE" >/dev/null || log_error "settime failed"
|
||||
set_keystate "KEY1" "GOAL" "hidden"
|
||||
set_keystate "KEY1" "STATE_DNSKEY" "unretentive"
|
||||
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
|
||||
set_keystate "KEY1" "STATE_ZRRSIG" "unretentive"
|
||||
set_keystate "KEY1" "STATE_DS" "omnipresent"
|
||||
check_key "KEY1" "$id"
|
||||
test "$ret" -eq 0 && key_save KEY1
|
||||
set_keytime "KEY1" "ACTIVE" "${now}"
|
||||
check_keytimes
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# named
|
||||
#
|
||||
@@ -64,7 +236,6 @@ next_key_event_threshold=100
|
||||
# infinite loops if there is an error.
|
||||
n=$((n + 1))
|
||||
echo_i "waiting for kasp signing changes to take effect ($n)"
|
||||
ret=0
|
||||
|
||||
_wait_for_done_apexnsec() {
|
||||
while read -r zone; do
|
||||
@@ -85,6 +256,18 @@ retry_quiet 30 _wait_for_done_apexnsec || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Test max-zone-ttl rejects zones with too high TTL.
|
||||
n=$((n + 1))
|
||||
echo_i "check that max-zone-ttl rejects zones with too high TTL ($n)"
|
||||
ret=0
|
||||
set_zone "max-zone-ttl.kasp"
|
||||
grep "loading from master file ${ZONE}.db failed: out of range" "ns3/named.run" >/dev/null || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# Zone: default.kasp.
|
||||
#
|
||||
set_keytimes_csk_policy() {
|
||||
# The first key is immediately published and activated.
|
||||
created=$(key_get KEY1 CREATED)
|
||||
@@ -92,11 +275,16 @@ set_keytimes_csk_policy() {
|
||||
set_keytime "KEY1" "ACTIVE" "${created}"
|
||||
# The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
|
||||
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 86700
|
||||
# publish-safety (1h) plus zone-propagation-delay (300s) =
|
||||
# 86400 + 3600 + 300 = 90300.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 90300
|
||||
# Key lifetime is unlimited, so not setting RETIRED and REMOVED.
|
||||
}
|
||||
|
||||
# Check the zone with default kasp policy has loaded and is signed.
|
||||
set_zone "default.kasp"
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
# Key properties.
|
||||
set_keyrole "KEY1" "csk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
@@ -110,6 +298,240 @@ set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
|
||||
set_keystate "KEY1" "STATE_ZRRSIG" "rumoured"
|
||||
set_keystate "KEY1" "STATE_DS" "hidden"
|
||||
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
set_keytimes_csk_policy
|
||||
check_keytimes
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Trigger a keymgr run. Make sure the key files are not touched if there are
|
||||
# no modifications to the key metadata.
|
||||
n=$((n + 1))
|
||||
echo_i "make sure key files are untouched if metadata does not change ($n)"
|
||||
ret=0
|
||||
basefile=$(key_get KEY1 BASEFILE)
|
||||
privkey_stat=$(key_get KEY1 PRIVKEY_STAT)
|
||||
pubkey_stat=$(key_get KEY1 PUBKEY_STAT)
|
||||
state_stat=$(key_get KEY1 STATE_STAT)
|
||||
|
||||
nextpart $DIR/named.run >/dev/null
|
||||
rndccmd 10.53.0.3 loadkeys "$ZONE" >/dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
|
||||
wait_for_log 3 "keymgr: $ZONE done" $DIR/named.run || ret=1
|
||||
privkey_stat2=$(key_stat "${basefile}.private")
|
||||
pubkey_stat2=$(key_stat "${basefile}.key")
|
||||
state_stat2=$(key_stat "${basefile}.state")
|
||||
test "$privkey_stat" = "$privkey_stat2" || log_error "wrong private key file stat (expected $privkey_stat got $privkey_stat2)"
|
||||
test "$pubkey_stat" = "$pubkey_stat2" || log_error "wrong public key file stat (expected $pubkey_stat got $pubkey_stat2)"
|
||||
test "$state_stat" = "$state_stat2" || log_error "wrong state file stat (expected $state_stat got $state_stat2)"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "again ($n)"
|
||||
ret=0
|
||||
|
||||
nextpart $DIR/named.run >/dev/null
|
||||
rndccmd 10.53.0.3 loadkeys "$ZONE" >/dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
|
||||
wait_for_log 3 "keymgr: $ZONE done" $DIR/named.run || ret=1
|
||||
privkey_stat2=$(key_stat "${basefile}.private")
|
||||
pubkey_stat2=$(key_stat "${basefile}.key")
|
||||
state_stat2=$(key_stat "${basefile}.state")
|
||||
test "$privkey_stat" = "$privkey_stat2" || log_error "wrong private key file stat (expected $privkey_stat got $privkey_stat2)"
|
||||
test "$pubkey_stat" = "$pubkey_stat2" || log_error "wrong public key file stat (expected $pubkey_stat got $pubkey_stat2)"
|
||||
test "$state_stat" = "$state_stat2" || log_error "wrong state file stat (expected $state_stat got $state_stat2)"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Update zone.
|
||||
n=$((n + 1))
|
||||
echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db"
|
||||
rndccmd 10.53.0.3 reload "$ZONE" >/dev/null || log_error "rndc reload zone ${ZONE} failed"
|
||||
|
||||
update_is_signed() {
|
||||
ip_a=$1
|
||||
ip_d=$2
|
||||
|
||||
if [ "$ip_a" != "-" ]; then
|
||||
dig_with_opts "a.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n.a" || return 1
|
||||
grep "status: NOERROR" "dig.out.$DIR.test$n.a" >/dev/null || return 1
|
||||
grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_a}" "dig.out.$DIR.test$n.a" >/dev/null || return 1
|
||||
lines=$(get_keys_which_signed A 0 "dig.out.$DIR.test$n.a" | wc -l)
|
||||
test "$lines" -eq 1 || return 1
|
||||
get_keys_which_signed A 0 "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" >/dev/null || return 1
|
||||
fi
|
||||
|
||||
if [ "$ip_d" != "-" ]; then
|
||||
dig_with_opts "d.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n".d || return 1
|
||||
grep "status: NOERROR" "dig.out.$DIR.test$n".d >/dev/null || return 1
|
||||
grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_d}" "dig.out.$DIR.test$n".d >/dev/null || return 1
|
||||
lines=$(get_keys_which_signed A 0 "dig.out.$DIR.test$n".d | wc -l)
|
||||
test "$lines" -eq 1 || return 1
|
||||
get_keys_which_signed A 0 "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" >/dev/null || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
retry_quiet 10 update_is_signed "10.0.0.11" "10.0.0.44" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Move the private key file, a rekey event should not introduce replacement
|
||||
# keys.
|
||||
ret=0
|
||||
echo_i "test that if private key files are inaccessible this doesn't trigger a rollover ($n)"
|
||||
basefile=$(key_get KEY1 BASEFILE)
|
||||
mv "${basefile}.private" "${basefile}.offline"
|
||||
rndccmd 10.53.0.3 loadkeys "$ZONE" >/dev/null || log_error "rndc loadkeys zone ${ZONE} failed"
|
||||
wait_for_log 3 "zone $ZONE/IN (signed): zone_rekey:zone_verifykeys failed: some key files are missing" $DIR/named.run || ret=1
|
||||
mv "${basefile}.offline" "${basefile}.private"
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Nothing has changed.
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
set_keytimes_csk_policy
|
||||
check_keytimes
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
#
|
||||
# A zone with special characters.
|
||||
#
|
||||
set_zone "i-am.\":\;?&[]\@!\$*+,|=\.\(\)special.kasp."
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
# It is non-trivial to adapt the tests to deal with all possible different
|
||||
# escaping characters, so we will just try to verify the zone.
|
||||
dnssec_verify
|
||||
|
||||
#
|
||||
# Zone: dynamic.kasp
|
||||
#
|
||||
set_zone "dynamic.kasp"
|
||||
set_dynamic
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
# Key properties, timings and states same as above.
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
set_keytimes_csk_policy
|
||||
check_keytimes
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Update zone with nsupdate.
|
||||
n=$((n + 1))
|
||||
echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
(
|
||||
echo zone ${ZONE}
|
||||
echo server 10.53.0.3 "$PORT"
|
||||
echo update del "a.${ZONE}" 300 A 10.0.0.1
|
||||
echo update add "a.${ZONE}" 300 A 10.0.0.101
|
||||
echo update add "d.${ZONE}" 300 A 10.0.0.4
|
||||
echo send
|
||||
) | $NSUPDATE
|
||||
|
||||
retry_quiet 10 update_is_signed "10.0.0.101" "10.0.0.4" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Update zone with nsupdate (reverting the above change).
|
||||
n=$((n + 1))
|
||||
echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
(
|
||||
echo zone ${ZONE}
|
||||
echo server 10.53.0.3 "$PORT"
|
||||
echo update add "a.${ZONE}" 300 A 10.0.0.1
|
||||
echo update del "a.${ZONE}" 300 A 10.0.0.101
|
||||
echo update del "d.${ZONE}" 300 A 10.0.0.4
|
||||
echo send
|
||||
) | $NSUPDATE
|
||||
|
||||
retry_quiet 10 update_is_signed "10.0.0.1" "-" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
# Update zone with freeze/thaw.
|
||||
n=$((n + 1))
|
||||
echo_i "modify zone file and check that new record is signed for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
rndccmd 10.53.0.3 freeze "$ZONE" >/dev/null || log_error "rndc freeze zone ${ZONE} failed"
|
||||
sleep 1
|
||||
echo "d.${ZONE}. 300 A 10.0.0.44" >>"${DIR}/${ZONE}.db"
|
||||
rndccmd 10.53.0.3 thaw "$ZONE" >/dev/null || log_error "rndc thaw zone ${ZONE} failed"
|
||||
|
||||
retry_quiet 10 update_is_signed "10.0.0.1" "10.0.0.44" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# Zone: dynamic-inline-signing.kasp
|
||||
#
|
||||
set_zone "dynamic-inline-signing.kasp"
|
||||
set_dynamic
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
# Key properties, timings and states same as above.
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
set_keytimes_csk_policy
|
||||
check_keytimes
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Update zone with freeze/thaw.
|
||||
n=$((n + 1))
|
||||
echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
rndccmd 10.53.0.3 freeze "$ZONE" >/dev/null || log_error "rndc freeze zone ${ZONE} failed"
|
||||
sleep 1
|
||||
cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db"
|
||||
rndccmd 10.53.0.3 thaw "$ZONE" >/dev/null || log_error "rndc thaw zone ${ZONE} failed"
|
||||
|
||||
retry_quiet 10 update_is_signed || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# Zone: dynamic-signed-inline-signing.kasp
|
||||
#
|
||||
set_zone "dynamic-signed-inline-signing.kasp"
|
||||
set_dynamic
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
dnssec_verify
|
||||
# Ensure no zone_resigninc for the unsigned version of the zone is triggered.
|
||||
n=$((n + 1))
|
||||
echo_i "check if resigning the raw version of the zone is prevented for zone ${ZONE} ($n)"
|
||||
ret=0
|
||||
grep "zone_resigninc: zone $ZONE/IN (unsigned): enter" $DIR/named.run && ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# Zone: inline-signing.kasp
|
||||
#
|
||||
set_zone "inline-signing.kasp"
|
||||
set_policy "default" "1" "3600"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
# Key properties, timings and states same as above.
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
set_keytimes_csk_policy
|
||||
check_keytimes
|
||||
check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
#
|
||||
# Zone: checkds-ksk.kasp.
|
||||
#
|
||||
@@ -347,8 +769,9 @@ set_keytimes_algorithm_policy() {
|
||||
|
||||
# The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
|
||||
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
|
||||
# publish-safety (1h) plus zone-propagation-delay (300s) =
|
||||
# 86400 + 3600 + 300 = 90300.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
|
||||
# Key lifetime is 10 years, 315360000 seconds.
|
||||
set_addkeytime "KEY1" "RETIRED" "${published}" 315360000
|
||||
# The key is removed after the retire time plus DS TTL (1d),
|
||||
@@ -455,16 +878,53 @@ if [ $RSASHA1_SUPPORTED = 1 ]; then
|
||||
dnssec_verify
|
||||
fi
|
||||
|
||||
#
|
||||
# Zone: unsigned.kasp.
|
||||
#
|
||||
set_zone "unsigned.kasp"
|
||||
set_policy "none" "0" "0"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
|
||||
key_clear "KEY1"
|
||||
key_clear "KEY2"
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
check_apex
|
||||
check_subdomain
|
||||
# Make sure the zone file is untouched.
|
||||
n=$((n + 1))
|
||||
echo_i "Make sure the zonefile for zone ${ZONE} is not edited ($n)"
|
||||
ret=0
|
||||
diff "${DIR}/${ZONE}.db.infile" "${DIR}/${ZONE}.db" || ret=1
|
||||
test "$ret" -eq 0 || echo_i "failed"
|
||||
status=$((status + ret))
|
||||
|
||||
#
|
||||
# Zone: insecure.kasp.
|
||||
#
|
||||
set_zone "insecure.kasp"
|
||||
set_policy "insecure" "0" "0"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
|
||||
key_clear "KEY1"
|
||||
key_clear "KEY2"
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
|
||||
check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
check_apex
|
||||
check_subdomain
|
||||
|
||||
#
|
||||
# Zone: unlimited.kasp.
|
||||
#
|
||||
set_zone "unlimited.kasp"
|
||||
set_policy "unlimited" "1" "1234"
|
||||
set_server "ns3" "10.53.0.3"
|
||||
key_clear "KEY1"
|
||||
key_clear "KEY2"
|
||||
key_clear "KEY3"
|
||||
key_clear "KEY4"
|
||||
# Key properties.
|
||||
set_keyrole "KEY1" "csk"
|
||||
set_keylifetime "KEY1" "0"
|
||||
@@ -1260,10 +1720,10 @@ published=$(awk '{print $3}' <published.test${n}.key1)
|
||||
set_keytime "KEY1" "PUBLISHED" "${published}"
|
||||
set_keytime "KEY1" "ACTIVE" "${published}"
|
||||
published=$(key_get KEY1 PUBLISHED)
|
||||
# The DS can be published if the zone is fully signed.
|
||||
# This happens after max-zone-ttl (1d) plus
|
||||
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
|
||||
# The DS can be published if the DNSKEY and RRSIG records are OMNIPRESENT.
|
||||
# This happens after max-zone-ttl (1d) plus publish-safety (1h) plus
|
||||
# zone-propagation-delay (300s) = 86400 + 3600 + 300 = 90300.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
|
||||
# Key lifetime is 6 months, 315360000 seconds.
|
||||
set_addkeytime "KEY1" "RETIRED" "${published}" 16070400
|
||||
# The key is removed after the retire time plus DS TTL (1d), parent
|
||||
@@ -2026,9 +2486,9 @@ set_keytime "KEY1" "PUBLISHED" "${created}"
|
||||
set_keytime "KEY1" "ACTIVE" "${created}"
|
||||
# - The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (12h) plus
|
||||
# plus zone-propagation-delay (5m) =
|
||||
# 43200 + 300 = 43500.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43500
|
||||
# publish-safety (5m) plus zone-propagation-delay (5m) =
|
||||
# 43200 + 300 + 300 = 43800.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
|
||||
# - Key lifetime is unlimited, so not setting RETIRED and REMOVED.
|
||||
|
||||
# Various signing policy checks.
|
||||
@@ -2096,7 +2556,7 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "PUBLISHED" "${created}" -900
|
||||
set_addkeytime "KEY1" "ACTIVE" "${created}" -900
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 42600
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -2106,8 +2566,8 @@ dnssec_verify
|
||||
|
||||
# Next key event is when the zone signatures become OMNIPRESENT: max-zone-ttl
|
||||
# plus zone propagation delay plus retire safety minus the already elapsed
|
||||
# 900 seconds: 12h + 300s + 20m - 900 = 43500 - 900 = 42600 seconds
|
||||
check_next_key_event 42600
|
||||
# 900 seconds: 12h + 300s + 20m - 900 = 44700 - 900 = 43800 seconds
|
||||
check_next_key_event 43800
|
||||
|
||||
#
|
||||
# Zone: step3.enable-dnssec.autosign.
|
||||
@@ -2124,10 +2584,10 @@ check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The key was published and activated 43500 seconds ago (with settime).
|
||||
# - The key was published and activated 44700 seconds ago (with settime).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "PUBLISHED" "${created}" -43500
|
||||
set_addkeytime "KEY1" "ACTIVE" "${created}" -43500
|
||||
set_addkeytime "KEY1" "PUBLISHED" "${created}" -44700
|
||||
set_addkeytime "KEY1" "ACTIVE" "${created}" -44700
|
||||
set_keytime "KEY1" "SYNCPUBLISH" "${created}"
|
||||
|
||||
# Continue signing policy checks.
|
||||
@@ -2143,8 +2603,8 @@ check_cdslog "$DIR" "$ZONE" KEY1
|
||||
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "published" "$ZONE"
|
||||
# Next key event is when the DS can move to the OMNIPRESENT state. This occurs
|
||||
# when the parent propagation delay have passed, plus the DS TTL and retire
|
||||
# safety delay: 1h + 2h = 3h = 10800 seconds
|
||||
check_next_key_event 10800
|
||||
# safety delay: 1h + 2h + 20m = 3h20m = 12000 seconds
|
||||
check_next_key_event 12000
|
||||
|
||||
#
|
||||
# Zone: step4.enable-dnssec.autosign.
|
||||
@@ -3928,9 +4388,9 @@ check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when the DS becomes HIDDEN. This happens after the
|
||||
# parent propagation delay, and DS TTL:
|
||||
# 1h + 1d = 25h = 90000 seconds.
|
||||
check_next_key_event 90000
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 1h + 1d = 26h = 93600 seconds.
|
||||
check_next_key_event 93600
|
||||
|
||||
#
|
||||
# Zone: step2.going-insecure.kasp
|
||||
@@ -3996,8 +4456,8 @@ dnssec_verify
|
||||
|
||||
# Next key event is when the DS becomes HIDDEN. This happens after the
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 1d = 25h = 90000 seconds.
|
||||
check_next_key_event 90000
|
||||
# 1h + 1h + 1d = 26h = 93600 seconds.
|
||||
check_next_key_event 93600
|
||||
|
||||
#
|
||||
# Zone: step2.going-insecure-dynamic.kasp
|
||||
@@ -4191,11 +4651,12 @@ set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_keytime "KEY3" "PUBLISHED" "${created}"
|
||||
set_keytime "KEY3" "ACTIVE" "${created}"
|
||||
# - It takes TTLsig + Dprp to propagate the zone.
|
||||
# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
|
||||
# TTLsig: 6h (39600 seconds)
|
||||
# Dprp: 1h (3600 seconds)
|
||||
# Ipub: 7h (25200 seconds)
|
||||
Ipub=25200
|
||||
# publish-safety: 1h (3600 seconds)
|
||||
# Ipub: 8h (28800 seconds)
|
||||
Ipub=28800
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${Ipub}"
|
||||
# - The new ZSK is published and activated.
|
||||
created=$(key_get KEY4 CREATED)
|
||||
@@ -4264,12 +4725,12 @@ dnssec_verify
|
||||
|
||||
# Next key event is when all zone signatures are signed with the new
|
||||
# algorithm. This is the max-zone-ttl plus zone propagation delay
|
||||
# 6h + 1h. But three hours have already passed (the time it took to
|
||||
# make the DNSKEY omnipresent), so the next event should be scheduled
|
||||
# in 4 hour: 14400 seconds. Prevent intermittent
|
||||
# plus retire safety: 6h + 1h + 2h. But three hours have already passed
|
||||
# (the time it took to make the DNSKEY omnipresent), so the next event
|
||||
# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((14400 - time_passed))
|
||||
next_time=$((21600 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -4292,28 +4753,28 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
check_cdslog "$DIR" "$ZONE" KEY3
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 7 hours ago (25200 seconds).
|
||||
rollover_predecessor_keytimes -25200
|
||||
# - And retired 3 hours ago (10800 seconds).
|
||||
# - The old keys were activated 9 hours ago (32400 seconds).
|
||||
rollover_predecessor_keytimes -32400
|
||||
# - And retired 6 hours ago (21600 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -10800
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -21600
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -10800
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -21600
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
# - The new keys are published 7 hours ago.
|
||||
# - The new keys are published 9 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -25200
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -25200
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -32400
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -32400
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -25200
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -25200
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -32400
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -32400
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4326,9 +4787,9 @@ dnssec_verify
|
||||
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
|
||||
rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE"
|
||||
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
|
||||
# parent propagation delay, and DS TTL:
|
||||
# 1h + 2h = 3h = 10800 seconds.
|
||||
check_next_key_event 10800
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 2h + 2h = 5h = 18000 seconds.
|
||||
check_next_key_event 18000
|
||||
|
||||
#
|
||||
# Zone: step4.algorithm-roll.kasp
|
||||
@@ -4355,29 +4816,29 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 36 hours ago (129600 seconds).
|
||||
rollover_predecessor_keytimes -129600
|
||||
# - And retired 33 hours ago (118800 seconds).
|
||||
# - The old keys were activated 38 hours ago (136800 seconds).
|
||||
rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -118800
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -118800
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -126000
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
|
||||
# - The new keys are published 36 hours ago.
|
||||
# - The new keys are published 38 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -129600
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -129600
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -129600
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -129600
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4406,29 +4867,29 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 38 hours ago (136800 seconds)
|
||||
rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
# - The old keys were activated 40 hours ago (144000 seconds)
|
||||
rollover_predecessor_keytimes -144000
|
||||
# - And retired 37 hours ago (133200 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -133200
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -126000
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -133200
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
|
||||
# The new keys are published 40 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -144000
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -144000
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -144000
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -144000
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4437,12 +4898,12 @@ check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
|
||||
# after the max-zone-ttl plus zone propagation delay (6h + 1h)
|
||||
# minus the time already passed since the UNRETENTIVE state has
|
||||
# been reached (2h): 7h - 2h = 5h = 18000 seconds. Prevent intermittent
|
||||
# after the max-zone-ttl plus zone propagation delay plus retire safety
|
||||
# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
|
||||
# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((18000 - time_passed))
|
||||
next_time=$((25200 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -4460,29 +4921,29 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 45 hours ago (162000 seconds)
|
||||
rollover_predecessor_keytimes -162000
|
||||
# - And retired 42 hours ago (151200 seconds).
|
||||
# - The old keys were activated 47 hours ago (169200 seconds)
|
||||
rollover_predecessor_keytimes -169200
|
||||
# - And retired 44 hours ago (158400 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -151200
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -158400
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -151200
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -158400
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
|
||||
# The new keys are published 47 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -162000
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -162000
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -169200
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -169200
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -162000
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -162000
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -169200
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -169200
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4565,8 +5026,9 @@ set_keytime "KEY2" "ACTIVE" "${created}"
|
||||
# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
|
||||
# TTLsig: 6h (39600 seconds)
|
||||
# Dprp: 1h (3600 seconds)
|
||||
# Ipub: 7h (25200 seconds)
|
||||
Ipub=25200
|
||||
# publish-safety: 1h (3600 seconds)
|
||||
# Ipub: 8h (28800 seconds)
|
||||
Ipub=28800
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}"
|
||||
|
||||
# Continue signing policy checks.
|
||||
@@ -4620,13 +5082,14 @@ check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when all zone signatures are signed with the new algorithm.
|
||||
# This is the max-zone-ttl plus zone propagation delay: 6h + 1h. But three
|
||||
# hours have already passed (the time it took to make the DNSKEY omnipresent),
|
||||
# so the next event should be scheduled in 4 hour: 14400 seconds. Prevent
|
||||
# intermittent false positives on slow platforms by subtracting the number of
|
||||
# seconds which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((14400 - time_passed))
|
||||
# Next key event is when all zone signatures are signed with the new
|
||||
# algorithm. This is the max-zone-ttl plus zone propagation delay
|
||||
# plus retire safety: 6h + 1h + 2h. But three hours have already passed
|
||||
# (the time it took to make the DNSKEY omnipresent), so the next event
|
||||
# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((21600 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -4651,17 +5114,17 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
check_cdslog "$DIR" "$ZONE" KEY2
|
||||
|
||||
# Set expected key times:
|
||||
# - The old key was activated 7 hours ago (25200 seconds).
|
||||
csk_rollover_predecessor_keytimes -25200
|
||||
# - And was retired 3 hours ago (10800 seconds).
|
||||
# - The old key was activated 9 hours ago (32400 seconds).
|
||||
csk_rollover_predecessor_keytimes -32400
|
||||
# - And was retired 6 hours ago (21600 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -10800
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -21600
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 9 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -25200
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -25200
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -32400
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -32400
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
|
||||
|
||||
@@ -4675,9 +5138,9 @@ dnssec_verify
|
||||
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
|
||||
rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE"
|
||||
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
|
||||
# parent propagation delay, and DS TTL:
|
||||
# 1h + 2h = 3h = 10800 seconds.
|
||||
check_next_key_event 10800
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 2h + 2h = 5h = 18000 seconds.
|
||||
check_next_key_event 18000
|
||||
|
||||
#
|
||||
# Zone: step4.csk-algorithm-roll.kasp
|
||||
@@ -4701,17 +5164,17 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 36 hours ago (129600 seconds).
|
||||
csk_rollover_predecessor_keytimes -129600
|
||||
# - And retired 33 hours ago (118800 seconds).
|
||||
# - The old key was activated 38 hours ago (136800 seconds)
|
||||
csk_rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -118800
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 36 hours ago.
|
||||
# - The new key was published 38 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -129600
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -129600
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
@@ -4741,17 +5204,17 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old key was activated 38 hours ago (136800 seconds)
|
||||
csk_rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
# - The old key was activated 40 hours ago (144000 seconds)
|
||||
csk_rollover_predecessor_keytimes -144000
|
||||
# - And retired 37 hours ago (133200 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -133200
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 38 hours ago.
|
||||
# - The new key was published 40 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -144000
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -144000
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
@@ -4762,12 +5225,12 @@ check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
|
||||
# after the max-zone-ttl plus zone propagation delay (6h + 1h) minus the
|
||||
# time already passed since the UNRETENTIVE state has been reached (2h):
|
||||
# 7h - 2h = 5h = 18000 seconds. Prevent intermittent false positives on slow
|
||||
# platforms by subtracting the number of seconds which passed between key
|
||||
# creation and invoking 'rndc reconfig'.
|
||||
next_time=$((18000 - time_passed))
|
||||
# after the max-zone-ttl plus zone propagation delay plus retire safety
|
||||
# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
|
||||
# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((25200 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -4785,17 +5248,17 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 45 hours ago (162000 seconds)
|
||||
csk_rollover_predecessor_keytimes -162000
|
||||
# - And retired 42 hours ago (151200 seconds).
|
||||
# - The old keys were activated 47 hours ago (169200 seconds)
|
||||
csk_rollover_predecessor_keytimes -169200
|
||||
# - And retired 44 hours ago (158400 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -151200
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -158400
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 47 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -162000
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -162000
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -169200
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -169200
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
|
||||
@@ -1,569 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
import dns
|
||||
import dns.update
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
from isctest.kasp import (
|
||||
KeyProperties,
|
||||
KeyTimingMetadata,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"K*.private",
|
||||
"K*.backup",
|
||||
"K*.cmp",
|
||||
"K*.key",
|
||||
"K*.state",
|
||||
"*.axfr",
|
||||
"*.created",
|
||||
"dig.out*",
|
||||
"keyevent.out.*",
|
||||
"keygen.out.*",
|
||||
"keys",
|
||||
"published.test*",
|
||||
"python.out.*",
|
||||
"retired.test*",
|
||||
"rndc.dnssec.*.out.*",
|
||||
"rndc.zonestatus.out.*",
|
||||
"rrsig.out.*",
|
||||
"created.key-*",
|
||||
"unused.key-*",
|
||||
"verify.out.*",
|
||||
"zone.out.*",
|
||||
"ns*/K*.key",
|
||||
"ns*/K*.offline",
|
||||
"ns*/K*.private",
|
||||
"ns*/K*.state",
|
||||
"ns*/*.db",
|
||||
"ns*/*.db.infile",
|
||||
"ns*/*.db.signed",
|
||||
"ns*/*.db.signed.tmp",
|
||||
"ns*/*.jbk",
|
||||
"ns*/*.jnl",
|
||||
"ns*/*.zsk1",
|
||||
"ns*/*.zsk2",
|
||||
"ns*/dsset-*",
|
||||
"ns*/keygen.out.*",
|
||||
"ns*/keys",
|
||||
"ns*/ksk",
|
||||
"ns*/ksk/K*",
|
||||
"ns*/zsk",
|
||||
"ns*/zsk",
|
||||
"ns*/zsk/K*",
|
||||
"ns*/named-fips.conf",
|
||||
"ns*/settime.out.*",
|
||||
"ns*/signer.out.*",
|
||||
"ns*/zones",
|
||||
"ns*/policies/*.conf",
|
||||
"ns3/legacy-keys.*",
|
||||
"ns3/dynamic-signed-inline-signing.kasp.db.signed.signed",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def check_all(server, zone, policy, ksks, zsks, tsig=None):
|
||||
isctest.kasp.check_dnssecstatus(server, zone, ksks + zsks, policy=policy)
|
||||
isctest.kasp.check_apex(server, zone, ksks, zsks, tsig=tsig)
|
||||
isctest.kasp.check_subdomain(server, zone, ksks, zsks, tsig=tsig)
|
||||
isctest.kasp.check_dnssec_verify(server, zone)
|
||||
|
||||
|
||||
def set_keytimes_default_policy(kp):
|
||||
# The first key is immediately published and activated.
|
||||
kp.timing["Generated"] = kp.key.get_timing("Created")
|
||||
kp.timing["Published"] = kp.timing["Generated"]
|
||||
kp.timing["Active"] = kp.timing["Generated"]
|
||||
# The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
|
||||
# plus zone-propagation-delay (300s).
|
||||
kp.timing["PublishCDS"] = kp.timing["Published"] + timedelta(days=1, seconds=300)
|
||||
# Key lifetime is unlimited, so not setting 'Retired' nor 'Removed'.
|
||||
kp.timing["DNSKEYChange"] = kp.timing["Published"]
|
||||
kp.timing["DSChange"] = kp.timing["Published"]
|
||||
kp.timing["KRRSIGChange"] = kp.timing["Active"]
|
||||
kp.timing["ZRRSIGChange"] = kp.timing["Active"]
|
||||
|
||||
|
||||
def test_kasp_default(servers):
|
||||
server = servers["ns3"]
|
||||
|
||||
# check the zone with default kasp policy has loaded and is signed.
|
||||
isctest.log.info("check a zone with the default policy is signed")
|
||||
zone = "default.kasp"
|
||||
policy = "default"
|
||||
|
||||
# Key properties.
|
||||
# DNSKEY, RRSIG (ksk), RRSIG (zsk) are published. DS needs to wait.
|
||||
keyprops = [
|
||||
"csk 0 13 256 goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
|
||||
]
|
||||
expected = isctest.kasp.policy_to_properties(ttl=3600, keys=keyprops)
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
|
||||
isctest.kasp.check_zone_is_signed(server, zone)
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
set_keytimes_default_policy(expected[0])
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
check_all(server, zone, policy, keys, [])
|
||||
|
||||
# Trigger a keymgr run. Make sure the key files are not touched if there
|
||||
# are no modifications to the key metadata.
|
||||
isctest.log.info(
|
||||
"check that key files are untouched if there are no metadata changes"
|
||||
)
|
||||
key = keys[0]
|
||||
privkey_stat = os.stat(key.privatefile)
|
||||
pubkey_stat = os.stat(key.keyfile)
|
||||
state_stat = os.stat(key.statefile)
|
||||
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"loadkeys {zone}", log=False)
|
||||
watcher.wait_for_line(f"keymgr: {zone} done")
|
||||
|
||||
assert privkey_stat.st_mtime == os.stat(key.privatefile).st_mtime
|
||||
assert pubkey_stat.st_mtime == os.stat(key.keyfile).st_mtime
|
||||
assert state_stat.st_mtime == os.stat(key.statefile).st_mtime
|
||||
|
||||
# again
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"loadkeys {zone}", log=False)
|
||||
watcher.wait_for_line(f"keymgr: {zone} done")
|
||||
|
||||
assert privkey_stat.st_mtime == os.stat(key.privatefile).st_mtime
|
||||
assert pubkey_stat.st_mtime == os.stat(key.keyfile).st_mtime
|
||||
assert state_stat.st_mtime == os.stat(key.statefile).st_mtime
|
||||
|
||||
# modify unsigned zone file and check that new record is signed.
|
||||
isctest.log.info("check that an updated zone signs the new record")
|
||||
shutil.copyfile("ns3/template2.db.in", f"ns3/{zone}.db")
|
||||
server.rndc(f"reload {zone}", log=False)
|
||||
|
||||
def update_is_signed():
|
||||
parts = update.split()
|
||||
qname = parts[0]
|
||||
qtype = dns.rdatatype.from_text(parts[1])
|
||||
rdata = parts[2]
|
||||
return isctest.kasp.check_update_is_signed(
|
||||
server, zone, qname, qtype, rdata, keys, []
|
||||
)
|
||||
|
||||
expected_updates = [f"a.{zone}. A 10.0.0.11", f"d.{zone}. A 10.0.0.44"]
|
||||
for update in expected_updates:
|
||||
isctest.run.retry_with_timeout(update_is_signed, timeout=5)
|
||||
|
||||
# Move the private key file, a rekey event should not introduce
|
||||
# replacement keys.
|
||||
isctest.log.info("check that missing private key doesn't trigger rollover")
|
||||
shutil.move(f"{key.privatefile}", f"{key.path}.offline")
|
||||
expectmsg = "zone_rekey:zone_verifykeys failed: some key files are missing"
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"loadkeys {zone}", log=False)
|
||||
watcher.wait_for_line(f"zone {zone}/IN (signed): {expectmsg}")
|
||||
# Nothing has changed.
|
||||
expected[0].properties["private"] = False
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
check_all(server, zone, policy, keys, [])
|
||||
|
||||
# A zone that uses inline-signing.
|
||||
isctest.log.info("check an inline-signed zone with the default policy is signed")
|
||||
zone = "inline-signing.kasp"
|
||||
# Key properties.
|
||||
key1 = KeyProperties.default()
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
|
||||
expected = [key1]
|
||||
isctest.kasp.check_zone_is_signed(server, zone)
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
set_keytimes_default_policy(key1)
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
check_all(server, zone, policy, keys, [])
|
||||
|
||||
|
||||
def test_kasp_dynamic(servers):
|
||||
# Dynamic update test cases.
|
||||
server = servers["ns3"]
|
||||
|
||||
# Standard dynamic zone.
|
||||
isctest.log.info("check dynamic zone is updated and signed after update")
|
||||
zone = "dynamic.kasp"
|
||||
policy = "default"
|
||||
# Key properties.
|
||||
key1 = KeyProperties.default()
|
||||
expected = [key1]
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
|
||||
isctest.kasp.check_zone_is_signed(server, zone)
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
set_keytimes_default_policy(key1)
|
||||
expected = [key1]
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
check_all(server, zone, policy, keys, [])
|
||||
|
||||
# Update zone with nsupdate.
|
||||
def nsupdate():
|
||||
message = dns.update.UpdateMessage(zone)
|
||||
for update in updates:
|
||||
if update[0] == 0:
|
||||
message.delete(update[1], update[2], update[3])
|
||||
else:
|
||||
message.add(update[1], update[2], update[3], update[4])
|
||||
|
||||
try:
|
||||
response = isctest.query.udp(
|
||||
message, server.ip, server.ports.dns, timeout=3
|
||||
)
|
||||
assert response.rcode() == dns.rcode.NOERROR
|
||||
except dns.exception.Timeout:
|
||||
isctest.log.info(f"error: update timeout for {zone}")
|
||||
|
||||
isctest.log.debug(f"update of zone {zone} to server {server.ip} successful")
|
||||
|
||||
def update_is_signed():
|
||||
parts = update.split()
|
||||
qname = parts[0]
|
||||
qtype = dns.rdatatype.from_text(parts[1])
|
||||
rdata = parts[2]
|
||||
return isctest.kasp.check_update_is_signed(
|
||||
server, zone, qname, qtype, rdata, keys, []
|
||||
)
|
||||
|
||||
updates = [
|
||||
[0, f"a.{zone}.", "A", "10.0.0.1"],
|
||||
[1, f"a.{zone}.", 300, "A", "10.0.0.101"],
|
||||
[1, f"d.{zone}.", 300, "A", "10.0.0.4"],
|
||||
]
|
||||
nsupdate()
|
||||
|
||||
expected_updates = [f"a.{zone}. A 10.0.0.101", f"d.{zone}. A 10.0.0.4"]
|
||||
for update in expected_updates:
|
||||
isctest.run.retry_with_timeout(update_is_signed, timeout=5)
|
||||
|
||||
# Update zone with nsupdate (reverting the above change).
|
||||
updates = [
|
||||
[1, f"a.{zone}.", 300, "A", "10.0.0.1"],
|
||||
[0, f"a.{zone}.", "A", "10.0.0.101"],
|
||||
[0, f"d.{zone}.", "A", "10.0.0.4"],
|
||||
]
|
||||
nsupdate()
|
||||
|
||||
update = f"a.{zone}. A 10.0.0.1"
|
||||
isctest.run.retry_with_timeout(update_is_signed, timeout=5)
|
||||
|
||||
# Update zone with freeze/thaw.
|
||||
isctest.log.info("check dynamic zone is updated and signed after freeze and thaw")
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"freeze {zone}", log=False)
|
||||
watcher.wait_for_line(f"freezing zone '{zone}/IN': success")
|
||||
|
||||
time.sleep(1)
|
||||
with open(f"ns3/{zone}.db", "a", encoding="utf-8") as zonefile:
|
||||
zonefile.write(f"d.{zone}. 300 A 10.0.0.44\n")
|
||||
time.sleep(1)
|
||||
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"thaw {zone}", log=False)
|
||||
watcher.wait_for_line(f"thawing zone '{zone}/IN': success")
|
||||
|
||||
expected_updates = [f"a.{zone}. A 10.0.0.1", f"d.{zone}. A 10.0.0.44"]
|
||||
|
||||
for update in expected_updates:
|
||||
isctest.run.retry_with_timeout(update_is_signed, timeout=5)
|
||||
|
||||
# Dynamic, and inline-signing.
|
||||
zone = "dynamic-inline-signing.kasp"
|
||||
# Key properties.
|
||||
key1 = KeyProperties.default()
|
||||
expected = [key1]
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
|
||||
isctest.kasp.check_zone_is_signed(server, zone)
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
set_keytimes_default_policy(key1)
|
||||
expected = [key1]
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
check_all(server, zone, policy, keys, [])
|
||||
|
||||
# Update zone with freeze/thaw.
|
||||
isctest.log.info(
|
||||
"check dynamic inline-signed zone is updated and signed after freeze and thaw"
|
||||
)
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"freeze {zone}", log=False)
|
||||
watcher.wait_for_line(f"freezing zone '{zone}/IN': success")
|
||||
|
||||
time.sleep(1)
|
||||
shutil.copyfile("ns3/template2.db.in", f"ns3/{zone}.db")
|
||||
time.sleep(1)
|
||||
|
||||
with server.watch_log_from_here() as watcher:
|
||||
server.rndc(f"thaw {zone}", log=False)
|
||||
watcher.wait_for_line(f"thawing zone '{zone}/IN': success")
|
||||
|
||||
expected_updates = [f"a.{zone}. A 10.0.0.11", f"d.{zone}. A 10.0.0.44"]
|
||||
for update in expected_updates:
|
||||
isctest.run.retry_with_timeout(update_is_signed, timeout=5)
|
||||
|
||||
# Dynamic, signed, and inline-signing.
|
||||
isctest.log.info("check dynamic signed, and inline-signed zone")
|
||||
zone = "dynamic-signed-inline-signing.kasp"
|
||||
# Key properties.
|
||||
key1 = KeyProperties.default()
|
||||
# The ns3/setup.sh script sets all states to omnipresent.
|
||||
key1.metadata["DNSKEYState"] = "omnipresent"
|
||||
key1.metadata["KRRSIGState"] = "omnipresent"
|
||||
key1.metadata["ZRRSIGState"] = "omnipresent"
|
||||
key1.metadata["DSState"] = "omnipresent"
|
||||
expected = [key1]
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3/keys")
|
||||
isctest.kasp.check_zone_is_signed(server, zone)
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
check_all(server, zone, policy, keys, [])
|
||||
# Ensure no zone_resigninc for the unsigned version of the zone is triggered.
|
||||
assert f"zone_resigninc: zone {zone}/IN (unsigned): enter" not in "ns3/named.run"
|
||||
|
||||
|
||||
def test_kasp_special_cases(servers):
|
||||
server = servers["ns3"]
|
||||
|
||||
# Insecure zones.
|
||||
isctest.log.info("check insecure zones")
|
||||
|
||||
zone = "insecure.kasp"
|
||||
expected = []
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
isctest.kasp.check_dnssecstatus(server, zone, keys, policy="insecure")
|
||||
isctest.kasp.check_apex(server, zone, keys, [])
|
||||
isctest.kasp.check_subdomain(server, zone, keys, [])
|
||||
|
||||
zone = "unsigned.kasp"
|
||||
expected = []
|
||||
keys = isctest.kasp.keydir_to_keylist(zone, "ns3")
|
||||
isctest.kasp.check_keys(zone, keys, expected)
|
||||
isctest.kasp.check_dnssecstatus(server, zone, keys, policy=None)
|
||||
isctest.kasp.check_apex(server, zone, keys, [])
|
||||
isctest.kasp.check_subdomain(server, zone, keys, [])
|
||||
# Make sure the zone file is untouched.
|
||||
isctest.check.file_contents_equal(f"ns3/{zone}.db.infile", f"ns3/{zone}.db")
|
||||
|
||||
# A zone with special characters.
|
||||
isctest.log.info("check special characters")
|
||||
|
||||
zone = r'i-am.":\;?&[]\@!\$*+,|=\.\(\)special.kasp'
|
||||
# It is non-trivial to adapt the tests to deal with all possible different
|
||||
# escaping characters, so we will just try to verify the zone.
|
||||
isctest.kasp.check_dnssec_verify(server, zone)
|
||||
|
||||
# check that max-zone-ttl rejects zones with too high TTL.
|
||||
isctest.log.info("check max-zone-ttl rejects zones with too high TTL")
|
||||
zone = "max-zone-ttl.kasp"
|
||||
assert f"loading from master file {zone}.db failed: out of range" in server.log
|
||||
|
||||
|
||||
def test_kasp_dnssec_keygen():
|
||||
def keygen(zone, policy, keydir=None):
|
||||
if keydir is None:
|
||||
keydir = "."
|
||||
|
||||
keygen_command = [
|
||||
os.environ.get("KEYGEN"),
|
||||
"-K",
|
||||
keydir,
|
||||
"-k",
|
||||
policy,
|
||||
"-l",
|
||||
"kasp.conf",
|
||||
zone,
|
||||
]
|
||||
|
||||
return isctest.run.cmd(keygen_command, log_stdout=True).stdout.decode("utf-8")
|
||||
|
||||
# check that 'dnssec-keygen -k' (configured policy) creates valid files.
|
||||
lifetime = {
|
||||
"P1Y": int(timedelta(days=365).total_seconds()),
|
||||
"P30D": int(timedelta(days=30).total_seconds()),
|
||||
"P6M": int(timedelta(days=31 * 6).total_seconds()),
|
||||
}
|
||||
keyprops = [
|
||||
f"csk {lifetime['P1Y']} 13 256",
|
||||
f"ksk {lifetime['P1Y']} 8 2048",
|
||||
f"zsk {lifetime['P30D']} 8 2048",
|
||||
f"zsk {lifetime['P6M']} 8 3072",
|
||||
]
|
||||
keydir = "keys"
|
||||
out = keygen("kasp", "kasp", keydir)
|
||||
keys = isctest.kasp.keystr_to_keylist(out, keydir)
|
||||
expected = isctest.kasp.policy_to_properties(ttl=200, keys=keyprops)
|
||||
isctest.kasp.check_keys("kasp", keys, expected)
|
||||
|
||||
# check that 'dnssec-keygen -k' (default policy) creates valid files.
|
||||
keyprops = ["csk 0 13 256"]
|
||||
out = keygen("kasp", "default")
|
||||
keys = isctest.kasp.keystr_to_keylist(out)
|
||||
expected = isctest.kasp.policy_to_properties(ttl=3600, keys=keyprops)
|
||||
isctest.kasp.check_keys("kasp", keys, expected)
|
||||
|
||||
# check that 'dnssec-settime' by default does not edit key state file.
|
||||
key = keys[0]
|
||||
privatefile = f"{key.path}.private"
|
||||
keyfile = f"{key.path}.key"
|
||||
statefile = f"{key.path}.state"
|
||||
shutil.copyfile(privatefile, f"{privatefile}.backup")
|
||||
shutil.copyfile(keyfile, f"{keyfile}.backup")
|
||||
shutil.copyfile(statefile, f"{statefile}.backup")
|
||||
|
||||
created = key.get_timing("Created")
|
||||
publish = key.get_timing("Publish") + timedelta(hours=1)
|
||||
settime = [
|
||||
os.environ.get("SETTIME"),
|
||||
"-P",
|
||||
str(publish),
|
||||
key.path,
|
||||
]
|
||||
out = isctest.run.cmd(settime, log_stdout=True).stdout.decode("utf-8")
|
||||
|
||||
isctest.check.file_contents_equal(f"{key.path}.state", f"{key.path}.state.backup")
|
||||
assert key.get_metadata("Publish", file=key.privatefile) == str(publish)
|
||||
assert key.get_metadata("Publish", file=key.keyfile, comment=True) == str(publish)
|
||||
|
||||
# check that 'dnssec-settime -s' also sets publish time metadata and
|
||||
# states in key state file.
|
||||
now = KeyTimingMetadata.now()
|
||||
goal = "omnipresent"
|
||||
dnskey = "rumoured"
|
||||
krrsig = "rumoured"
|
||||
zrrsig = "omnipresent"
|
||||
ds = "hidden"
|
||||
keyprops = [
|
||||
f"csk 0 13 256 goal:{goal} dnskey:{dnskey} krrsig:{krrsig} zrrsig:{zrrsig} ds:{ds}",
|
||||
]
|
||||
expected = isctest.kasp.policy_to_properties(ttl=3600, keys=keyprops)
|
||||
expected[0].timing = {
|
||||
"Generated": created,
|
||||
"Published": now,
|
||||
"Active": created,
|
||||
"DNSKEYChange": now,
|
||||
"KRRSIGChange": now,
|
||||
"ZRRSIGChange": now,
|
||||
"DSChange": now,
|
||||
}
|
||||
|
||||
settime = [
|
||||
os.environ.get("SETTIME"),
|
||||
"-s",
|
||||
"-P",
|
||||
str(now),
|
||||
"-g",
|
||||
goal,
|
||||
"-k",
|
||||
dnskey,
|
||||
str(now),
|
||||
"-r",
|
||||
krrsig,
|
||||
str(now),
|
||||
"-z",
|
||||
zrrsig,
|
||||
str(now),
|
||||
"-d",
|
||||
ds,
|
||||
str(now),
|
||||
key.path,
|
||||
]
|
||||
out = isctest.run.cmd(settime, log_stdout=True).stdout.decode("utf-8")
|
||||
isctest.kasp.check_keys("kasp", keys, expected)
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
|
||||
# check that 'dnssec-settime -s' also unsets publish time metadata and
|
||||
# states in key state file.
|
||||
now = KeyTimingMetadata.now()
|
||||
keyprops = ["csk 0 13 256"]
|
||||
expected = isctest.kasp.policy_to_properties(ttl=3600, keys=keyprops)
|
||||
expected[0].timing = {
|
||||
"Generated": created,
|
||||
"Active": created,
|
||||
}
|
||||
|
||||
settime = [
|
||||
os.environ.get("SETTIME"),
|
||||
"-s",
|
||||
"-P",
|
||||
"none",
|
||||
"-g",
|
||||
"none",
|
||||
"-k",
|
||||
"none",
|
||||
str(now),
|
||||
"-z",
|
||||
"none",
|
||||
str(now),
|
||||
"-r",
|
||||
"none",
|
||||
str(now),
|
||||
"-d",
|
||||
"none",
|
||||
str(now),
|
||||
key.path,
|
||||
]
|
||||
out = isctest.run.cmd(settime, log_stdout=True).stdout.decode("utf-8")
|
||||
isctest.kasp.check_keys("kasp", keys, expected)
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
|
||||
# check that 'dnssec-settime -s' also sets active time metadata and states in key state file (uppercase)
|
||||
soon = now + timedelta(hours=2)
|
||||
goal = "hidden"
|
||||
dnskey = "unretentive"
|
||||
krrsig = "omnipresent"
|
||||
zrrsig = "unretentive"
|
||||
ds = "omnipresent"
|
||||
keyprops = [
|
||||
f"csk 0 13 256 goal:{goal} dnskey:{dnskey} krrsig:{krrsig} zrrsig:{zrrsig} ds:{ds}",
|
||||
]
|
||||
expected = isctest.kasp.policy_to_properties(ttl=3600, keys=keyprops)
|
||||
expected[0].timing = {
|
||||
"Generated": created,
|
||||
"Active": soon,
|
||||
"DNSKEYChange": soon,
|
||||
"KRRSIGChange": soon,
|
||||
"ZRRSIGChange": soon,
|
||||
"DSChange": soon,
|
||||
}
|
||||
|
||||
settime = [
|
||||
os.environ.get("SETTIME"),
|
||||
"-s",
|
||||
"-A",
|
||||
str(soon),
|
||||
"-g",
|
||||
"HIDDEN",
|
||||
"-k",
|
||||
"UNRETENTIVE",
|
||||
str(soon),
|
||||
"-z",
|
||||
"UNRETENTIVE",
|
||||
str(soon),
|
||||
"-r",
|
||||
"OMNIPRESENT",
|
||||
str(soon),
|
||||
"-d",
|
||||
"OMNIPRESENT",
|
||||
str(soon),
|
||||
key.path,
|
||||
]
|
||||
out = isctest.run.cmd(settime, log_stdout=True).stdout.decode("utf-8")
|
||||
isctest.kasp.check_keys("kasp", keys, expected)
|
||||
isctest.kasp.check_keytimes(keys, expected)
|
||||
@@ -10,14 +10,19 @@
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from datetime import timedelta
|
||||
import difflib
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
from typing import List, Optional
|
||||
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
from isctest.kasp import KeyTimingMetadata
|
||||
from isctest.kasp import (
|
||||
Key,
|
||||
KeyTimingMetadata,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
@@ -84,6 +89,31 @@ def between(value, start, end):
|
||||
return start < value < end
|
||||
|
||||
|
||||
def check_file_contents_equal(file1, file2):
|
||||
def normalize_line(line):
|
||||
# remove trailing&leading whitespace and replace multiple whitespaces
|
||||
return " ".join(line.split())
|
||||
|
||||
def read_lines(file_path):
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
return [normalize_line(line) for line in file.readlines()]
|
||||
|
||||
lines1 = read_lines(file1)
|
||||
lines2 = read_lines(file2)
|
||||
|
||||
differ = difflib.Differ()
|
||||
diff = differ.compare(lines1, lines2)
|
||||
|
||||
for line in diff:
|
||||
assert not line.startswith("+ ") and not line.startswith(
|
||||
"- "
|
||||
), f'file contents of "{file1}" and "{file2}" differ'
|
||||
|
||||
|
||||
def keystr_to_keylist(keystr: str, keydir: Optional[str] = None) -> List[Key]:
|
||||
return [Key(name, keydir) for name in keystr.split()]
|
||||
|
||||
|
||||
def ksr(zone, policy, action, options="", raise_on_exception=True):
|
||||
ksr_command = [
|
||||
os.environ.get("KSR"),
|
||||
@@ -485,14 +515,14 @@ def test_ksr_common(servers):
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None)
|
||||
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
out, _ = ksr(zone, policy, "keygen", options="-i now -e +1y")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out)
|
||||
zsks = keystr_to_keylist(out)
|
||||
assert len(zsks) == 2
|
||||
|
||||
lifetime = timedelta(days=31 * 6)
|
||||
@@ -502,7 +532,7 @@ def test_ksr_common(servers):
|
||||
# in the given key directory
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 2
|
||||
|
||||
lifetime = timedelta(days=31 * 6)
|
||||
@@ -545,22 +575,18 @@ def test_ksr_common(servers):
|
||||
# check that 'dnssec-ksr keygen' selects pregenerated keys for
|
||||
# the same time bundle
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {now} -e +1y")
|
||||
selected_zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
selected_zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(selected_zsks) == 2
|
||||
for index, key in enumerate(selected_zsks):
|
||||
assert zsks[index] == key
|
||||
isctest.check.file_contents_equal(
|
||||
f"{key.path}.private", f"{key.path}.private.backup"
|
||||
)
|
||||
isctest.check.file_contents_equal(f"{key.path}.key", f"{key.path}.key.backup")
|
||||
isctest.check.file_contents_equal(
|
||||
f"{key.path}.state", f"{key.path}.state.backup"
|
||||
)
|
||||
check_file_contents_equal(f"{key.path}.private", f"{key.path}.private.backup")
|
||||
check_file_contents_equal(f"{key.path}.key", f"{key.path}.key.backup")
|
||||
check_file_contents_equal(f"{key.path}.state", f"{key.path}.state.backup")
|
||||
|
||||
# check that 'dnssec-ksr keygen' generates only necessary keys for
|
||||
# overlapping time bundle
|
||||
out, err = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {now} -e +2y -v 1")
|
||||
overlapping_zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
overlapping_zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(overlapping_zsks) == 4
|
||||
|
||||
verbose = err.split()
|
||||
@@ -571,24 +597,24 @@ def test_ksr_common(servers):
|
||||
selected += 1
|
||||
if "Generating" in output:
|
||||
generated += 1
|
||||
# Subtract if there was a key collision.
|
||||
if "collide" in output:
|
||||
generated -= 1
|
||||
|
||||
assert selected == 2
|
||||
assert generated == 2
|
||||
for index, key in enumerate(overlapping_zsks):
|
||||
if index < 2:
|
||||
assert zsks[index] == key
|
||||
isctest.check.file_contents_equal(
|
||||
check_file_contents_equal(
|
||||
f"{key.path}.private", f"{key.path}.private.backup"
|
||||
)
|
||||
isctest.check.file_contents_equal(
|
||||
f"{key.path}.key", f"{key.path}.key.backup"
|
||||
)
|
||||
isctest.check.file_contents_equal(
|
||||
f"{key.path}.state", f"{key.path}.state.backup"
|
||||
)
|
||||
check_file_contents_equal(f"{key.path}.key", f"{key.path}.key.backup")
|
||||
check_file_contents_equal(f"{key.path}.state", f"{key.path}.state.backup")
|
||||
|
||||
# run 'dnssec-ksr keygen' again with verbosity 0
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {now} -e +2y")
|
||||
overlapping_zsks2 = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
overlapping_zsks2 = keystr_to_keylist(out, zskdir)
|
||||
assert len(overlapping_zsks2) == 4
|
||||
check_keys(overlapping_zsks2, lifetime)
|
||||
for index, key in enumerate(overlapping_zsks2):
|
||||
@@ -683,7 +709,7 @@ def test_ksr_lastbundle(servers):
|
||||
kskdir = "ns1/offline"
|
||||
offset = -timedelta(days=365)
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i -1y -e +1d -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None, offset=offset)
|
||||
@@ -691,7 +717,7 @@ def test_ksr_lastbundle(servers):
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i -1y -e +1d")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 2
|
||||
|
||||
lifetime = timedelta(days=31 * 6)
|
||||
@@ -762,7 +788,7 @@ def test_ksr_inthemiddle(servers):
|
||||
kskdir = "ns1/offline"
|
||||
offset = -timedelta(days=365)
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i -1y -e +1y -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None, offset=offset)
|
||||
@@ -770,7 +796,7 @@ def test_ksr_inthemiddle(servers):
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i -1y -e +1y")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 4
|
||||
|
||||
lifetime = timedelta(days=31 * 6)
|
||||
@@ -842,13 +868,13 @@ def check_ksr_rekey_logs_error(server, zone, policy, offset, end):
|
||||
then = now + offset
|
||||
until = now + end
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i {then} -e {until} -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
# key generation
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {then} -e {until}")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 2
|
||||
|
||||
# create request
|
||||
@@ -915,7 +941,7 @@ def test_ksr_unlimited(servers):
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +2y -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 1
|
||||
|
||||
check_keys(ksks, None)
|
||||
@@ -923,7 +949,7 @@ def test_ksr_unlimited(servers):
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +2y")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 1
|
||||
|
||||
lifetime = None
|
||||
@@ -1032,7 +1058,7 @@ def test_ksr_twotone(servers):
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 2
|
||||
|
||||
ksks_defalg = []
|
||||
@@ -1056,7 +1082,7 @@ def test_ksr_twotone(servers):
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
# First algorithm keys have a lifetime of 3 months, so there should
|
||||
# be 4 created keys. Second algorithm keys have a lifetime of 5
|
||||
# months, so there should be 3 created keys. While only two time
|
||||
@@ -1150,7 +1176,7 @@ def test_ksr_kskroll(servers):
|
||||
# create ksk
|
||||
kskdir = "ns1/offline"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
|
||||
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
|
||||
ksks = keystr_to_keylist(out, kskdir)
|
||||
assert len(ksks) == 2
|
||||
|
||||
lifetime = timedelta(days=31 * 6)
|
||||
@@ -1159,7 +1185,7 @@ def test_ksr_kskroll(servers):
|
||||
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
|
||||
zskdir = "ns1"
|
||||
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
|
||||
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
|
||||
zsks = keystr_to_keylist(out, zskdir)
|
||||
assert len(zsks) == 1
|
||||
|
||||
check_keys(zsks, None)
|
||||
|
||||
@@ -385,7 +385,7 @@ $DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A >dig.out.ns3.test$n.1 2>&1
|
||||
grep "NOERROR" dig.out.ns3.test$n.1 >/dev/null || ret=1
|
||||
grep "flags:.* ad" dig.out.ns3.test$n.1 >/dev/null || ret=1
|
||||
# Sanity check: the authoritative server should have been queried.
|
||||
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" >/dev/null || ret=1
|
||||
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/NS/IN'" >/dev/null || ret=1
|
||||
# Reconfigure ns2 so that the zone can be mirrored on ns3.
|
||||
sed '/^zone "initially-unavailable" {$/,/^};$/ {
|
||||
s/10.53.0.254/10.53.0.3/
|
||||
@@ -403,7 +403,7 @@ $DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A >dig.out.ns3.test$n.2 2>&1
|
||||
grep "NOERROR" dig.out.ns3.test$n.2 >/dev/null || ret=1
|
||||
grep "flags:.* ad" dig.out.ns3.test$n.2 >/dev/null || ret=1
|
||||
# Ensure the authoritative server was not queried.
|
||||
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" >/dev/null && ret=1
|
||||
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/NS/IN'" >/dev/null && ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
@@ -434,7 +434,7 @@ $DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A >dig.out.ns3.test$n 2>&1 |
|
||||
grep "NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
|
||||
grep "flags:.* ad" dig.out.ns3.test$n >/dev/null || ret=1
|
||||
# Sanity check: the authoritative server should have been queried.
|
||||
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" >/dev/null || ret=1
|
||||
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/NS/IN'" >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
||||
@@ -104,9 +104,10 @@ def create_response(msg):
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "hooray"))
|
||||
elif rrtype == NS:
|
||||
# NS a.b.
|
||||
# This is only returned if a query for b.stale/NS has been made
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.a.b.stale."))
|
||||
r.additional.append(
|
||||
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.3")
|
||||
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
|
||||
)
|
||||
elif rrtype == SOA:
|
||||
# SOA a.b.
|
||||
@@ -126,7 +127,7 @@ def create_response(msg):
|
||||
r.flags |= dns.flags.AA
|
||||
if rrtype == A:
|
||||
r.answer.append(
|
||||
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.3")
|
||||
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
|
||||
)
|
||||
else:
|
||||
# NODATA.
|
||||
|
||||
@@ -127,12 +127,14 @@ ADDR a.bit.longer.ns.name.good.
|
||||
ADDR ns2.good.
|
||||
ADDR ns3.good.
|
||||
ADDR ns3.good.
|
||||
NS a.bit.longer.ns.name.good.
|
||||
NS bit.longer.ns.name.good.
|
||||
NS boing.good.
|
||||
NS good.
|
||||
NS longer.ns.name.good.
|
||||
NS name.good.
|
||||
NS ns.name.good.
|
||||
NS ns3.good.
|
||||
NS zoop.boing.good.
|
||||
__EOF
|
||||
cat <<__EOF | diff ans3/query.log - >/dev/null || ret=1
|
||||
@@ -165,11 +167,13 @@ ADDR a.bit.longer.ns.name.good.
|
||||
ADDR ns2.good.
|
||||
ADDR ns3.good.
|
||||
ADDR ns3.good.
|
||||
NS a.bit.longer.ns.name.good.
|
||||
NS bit.longer.ns.name.good.
|
||||
NS boing.good.
|
||||
NS longer.ns.name.good.
|
||||
NS name.good.
|
||||
NS ns.name.good.
|
||||
NS ns3.good.
|
||||
NS zoop.boing.good.
|
||||
__EOF
|
||||
cat <<__EOF | diff ans3/query.log - >/dev/null || ret=1
|
||||
@@ -221,6 +225,7 @@ ADDR ns3.bad.
|
||||
ADDR ns3.bad.
|
||||
NS boing.bad.
|
||||
NS name.bad.
|
||||
NS ns3.bad.
|
||||
__EOF
|
||||
cat <<__EOF | diff ans3/query.log - >/dev/null || ret=1
|
||||
ADDR icky.icky.icky.ptang.zoop.boing.bad.
|
||||
@@ -271,6 +276,7 @@ ADDR ns3.ugly.
|
||||
NS boing.ugly.
|
||||
NS name.ugly.
|
||||
NS name.ugly.
|
||||
NS ns3.ugly.
|
||||
__EOF
|
||||
echo "ADDR icky.icky.icky.ptang.zoop.boing.ugly." | diff ans3/query.log - >/dev/null || ret=1
|
||||
echo "ADDR icky.icky.icky.ptang.zoop.boing.ugly." | diff ans4/query.log - >/dev/null || ret=1
|
||||
@@ -302,11 +308,13 @@ ADDR a.bit.longer.ns.name.slow.
|
||||
ADDR ns2.slow.
|
||||
ADDR ns3.slow.
|
||||
ADDR ns3.slow.
|
||||
NS a.bit.longer.ns.name.slow.
|
||||
NS bit.longer.ns.name.slow.
|
||||
NS boing.slow.
|
||||
NS longer.ns.name.slow.
|
||||
NS name.slow.
|
||||
NS ns.name.slow.
|
||||
NS ns3.slow.
|
||||
NS slow.
|
||||
NS zoop.boing.slow.
|
||||
__EOF
|
||||
@@ -340,6 +348,7 @@ NS 8.f.4.0.1.0.0.2.ip6.arpa.
|
||||
NS 0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
|
||||
NS 0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
|
||||
NS 0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
|
||||
NS 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
|
||||
PTR 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
@@ -362,12 +371,14 @@ ADDR a.bit.longer.ns.name.good.
|
||||
ADDR ns2.good.
|
||||
ADDR ns3.good.
|
||||
ADDR ns3.good.
|
||||
NS a.bit.longer.ns.name.good.
|
||||
NS bit.longer.ns.name.good.
|
||||
NS boing.good.
|
||||
NS good.
|
||||
NS longer.ns.name.good.
|
||||
NS name.good.
|
||||
NS ns.name.good.
|
||||
NS ns3.good.
|
||||
NS zoop.boing.good.
|
||||
__EOF
|
||||
cat <<__EOF | diff ans3/query.log - >/dev/null || ret=1
|
||||
@@ -449,6 +460,7 @@ grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n >/dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log >ans2/query.log.sorted
|
||||
cat <<__EOF | diff ans2/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
ADDR ns2.stale.
|
||||
NS b.stale.
|
||||
@@ -457,7 +469,9 @@ __EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log >ans4/query.log.sorted
|
||||
cat <<__EOF | diff ans4/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
NS a.b.stale.
|
||||
NS b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
@@ -476,6 +490,7 @@ grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n >/dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log >ans2/query.log.sorted
|
||||
cat <<__EOF | diff ans2/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
ADDR ns2.stale.
|
||||
NS b.stale.
|
||||
@@ -483,7 +498,9 @@ __EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log >ans4/query.log.sorted
|
||||
cat <<__EOF | diff ans4/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
NS a.b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
@@ -519,6 +536,7 @@ grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n >/dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log >ans2/query.log.sorted
|
||||
cat <<__EOF | diff ans2/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
ADDR ns2.stale.
|
||||
NS b.stale.
|
||||
@@ -527,7 +545,9 @@ __EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log >ans4/query.log.sorted
|
||||
cat <<__EOF | diff ans4/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
NS a.b.stale.
|
||||
NS b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
@@ -546,6 +566,7 @@ grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n >/dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log >ans2/query.log.sorted
|
||||
cat <<__EOF | diff ans2/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
ADDR ns2.stale.
|
||||
NS b.stale.
|
||||
@@ -553,7 +574,9 @@ __EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log >ans4/query.log.sorted
|
||||
cat <<__EOF | diff ans4/query.log.sorted - >/dev/null || ret=1
|
||||
ADDR ns.a.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
NS a.b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
$TTL 60
|
||||
$TTL 120
|
||||
|
||||
big. IN SOA ns.big. hostmaster.ns.big. 1 0 0 0 60
|
||||
big. IN SOA ns.big. hostmaster.ns.big. 1 0 0 0 120
|
||||
big. IN NS ns.big.
|
||||
ns.big. IN A 10.53.0.1
|
||||
|
||||
|
||||
@@ -280,11 +280,11 @@ echo_i "checking that priority names under the max-types-per-name limit get cach
|
||||
|
||||
# Query for NXDOMAIN for items on our priority list - these should get cached
|
||||
for rrtype in AAAA MX NS; do
|
||||
check_manytypes 1 manytypes.big "${rrtype}" NOERROR big SOA 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "${rrtype}" NOERROR big SOA 120 || ret=1
|
||||
done
|
||||
# Wait at least 1 second
|
||||
for rrtype in AAAA MX NS; do
|
||||
check_manytypes 2 manytypes.big "${rrtype}" NOERROR big SOA "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "${rrtype}" NOERROR big SOA "" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
@@ -299,13 +299,13 @@ echo_i "checking that NXDOMAIN names under the max-types-per-name limit get cach
|
||||
|
||||
# Query for 10 NXDOMAIN types
|
||||
for ntype in $(seq 65270 65279); do
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR big SOA 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR big SOA 120 || ret=1
|
||||
done
|
||||
# Wait at least 1 second
|
||||
sleep 1
|
||||
# Query for 10 NXDOMAIN types again - these should be cached
|
||||
for ntype in $(seq 65270 65279); do
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR big SOA "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR big SOA "" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
@@ -318,13 +318,13 @@ echo_i "checking that existing names under the max-types-per-name limit get cach
|
||||
|
||||
# Limited to 10 types - these should be cached and the previous record should be evicted
|
||||
for ntype in $(seq 65280 65289); do
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
# Wait at least one second
|
||||
sleep 1
|
||||
# Limited to 10 types - these should be cached
|
||||
for ntype in $(seq 65280 65289); do
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" "" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
@@ -356,11 +356,11 @@ echo_i "checking that priority NXDOMAIN names over the max-types-per-name limit
|
||||
|
||||
# Query for NXDOMAIN for items on our priority list - these should get cached
|
||||
for rrtype in AAAA MX NS; do
|
||||
check_manytypes 1 manytypes.big "${rrtype}" NOERROR big SOA 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "${rrtype}" NOERROR big SOA 120 || ret=1
|
||||
done
|
||||
# Wait at least 1 second
|
||||
for rrtype in AAAA MX NS; do
|
||||
check_manytypes 2 manytypes.big "${rrtype}" NOERROR big SOA "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "${rrtype}" NOERROR big SOA "" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
@@ -372,11 +372,11 @@ ret=0
|
||||
echo_i "checking that priority name over the max-types-per-name get cached ($n)"
|
||||
|
||||
# Query for an item on our priority list - it should get cached
|
||||
check_manytypes 1 manytypes.big "A" NOERROR manytypes.big A 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "A" NOERROR manytypes.big A 120 || ret=1
|
||||
# Wait at least 1 second
|
||||
sleep 1
|
||||
# Query the same name again - it should be in the cache
|
||||
check_manytypes 2 manytypes.big "A" NOERROR big manytypes.A "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "A" NOERROR big manytypes.A "" 120 || ret=1
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
@@ -389,7 +389,7 @@ ret=0
|
||||
echo_i "checking that priority name over the max-types-per-name don't get evicted ($n)"
|
||||
|
||||
# Query for an item on our priority list - it should get cached
|
||||
check_manytypes 1 manytypes.big "A" NOERROR manytypes.big A 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "A" NOERROR manytypes.big A 120 || ret=1
|
||||
# Query for 10 more types - this should not evict A record
|
||||
for ntype in $(seq 65280 65289); do
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big || ret=1
|
||||
@@ -397,9 +397,9 @@ done
|
||||
# Wait at least 1 second
|
||||
sleep 1
|
||||
# Query the same name again - it should be in the cache
|
||||
check_manytypes 2 manytypes.big "A" NOERROR manytypes.big A "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "A" NOERROR manytypes.big A "" 120 || ret=1
|
||||
# This one was first in the list and should have been evicted
|
||||
check_manytypes 2 manytypes.big "TYPE65280" NOERROR manytypes.big TYPE65280 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "TYPE65280" NOERROR manytypes.big TYPE65280 120 || ret=1
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
@@ -413,21 +413,21 @@ echo_i "checking that non-priority types cause eviction ($n)"
|
||||
|
||||
# Everything on top of that will cause the cache eviction
|
||||
for ntype in $(seq 65280 65299); do
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
# Wait at least one second
|
||||
sleep 1
|
||||
# These should have TTL != 60 now
|
||||
# These should have TTL != 120 now
|
||||
for ntype in $(seq 65290 65299); do
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" "" 120 || ret=1
|
||||
done
|
||||
# These should have been evicted
|
||||
for ntype in $(seq 65280 65289); do
|
||||
check_manytypes 3 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 3 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
# These should have been evicted by the previous block
|
||||
for ntype in $(seq 65290 65299); do
|
||||
check_manytypes 4 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 4 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
@@ -442,25 +442,25 @@ echo_i "checking that signed names under the max-types-per-name limit get cached
|
||||
|
||||
# Go through the 10 items, this should result in 20 items (type + rrsig(type))
|
||||
for ntype in $(seq 65280 65289); do
|
||||
check_manytypes 1 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 1 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
|
||||
# Wait at least one second
|
||||
sleep 1
|
||||
|
||||
# These should have TTL != 60 now
|
||||
# These should have TTL != 120 now
|
||||
for ntype in $(seq 65285 65289); do
|
||||
check_manytypes 2 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" "" 120 || ret=1
|
||||
done
|
||||
|
||||
# These should have been evicted
|
||||
for ntype in $(seq 65280 65284); do
|
||||
check_manytypes 3 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 3 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
|
||||
# These should have been evicted by the previous block
|
||||
for ntype in $(seq 65285 65289); do
|
||||
check_manytypes 4 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 4 manytypes.signed "TYPE${ntype}" NOERROR manytypes.signed "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
@@ -475,12 +475,12 @@ echo_i "checking that lifting the limit will allow everything to get cached ($n)
|
||||
ns3_reset ns3/named6.conf.in
|
||||
|
||||
for ntype in $(seq 65280 65534); do
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 60 || ret=1
|
||||
check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" 120 || ret=1
|
||||
done
|
||||
# Wait at least one second
|
||||
sleep 1
|
||||
for ntype in $(seq 65280 65534); do
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" "" 60 || ret=1
|
||||
check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR manytypes.big "TYPE${ntype}" "" 120 || ret=1
|
||||
done
|
||||
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.11;
|
||||
notify-source 10.53.0.11;
|
||||
transfer-source 10.53.0.11;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.11; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
};
|
||||
@@ -24,5 +24,6 @@ copy_setports ns5/named.conf.in ns5/named.conf
|
||||
copy_setports ns6/named.conf.in ns6/named.conf
|
||||
copy_setports ns7/named1.conf.in ns7/named.conf
|
||||
copy_setports ns9/named.conf.in ns9/named.conf
|
||||
copy_setports ns11/named.conf.in ns11/named.conf
|
||||
|
||||
(cd ns6 && $SHELL keygen.sh)
|
||||
|
||||
@@ -729,10 +729,10 @@ if ${FEATURETEST} --enable-querytrace; then
|
||||
grep "status: SERVFAIL" dig.ns5.out.${n} >/dev/null || ret=1
|
||||
check_namedrun() {
|
||||
nextpartpeek ns5/named.run >nextpart.out.${n}
|
||||
grep 'resolving tcpalso.no-questions/A for [^:]*: empty question section, accepting it anyway as TC=1' nextpart.out.${n} >/dev/null || return 1
|
||||
grep '(tcpalso.no-questions/A): connecting via TCP' nextpart.out.${n} >/dev/null || return 1
|
||||
grep 'resolving tcpalso.no-questions/A for [^:]*: empty question section$' nextpart.out.${n} >/dev/null || return 1
|
||||
grep '(tcpalso.no-questions/A): nextitem' nextpart.out.${n} >/dev/null || return 1
|
||||
grep 'resolving tcpalso.no-questions/NS for [^:]*: empty question section, accepting it anyway as TC=1' nextpart.out.${n} >/dev/null || return 1
|
||||
grep '(tcpalso.no-questions/NS): connecting via TCP' nextpart.out.${n} >/dev/null || return 1
|
||||
grep 'resolving tcpalso.no-questions/NS for [^:]*: empty question section$' nextpart.out.${n} >/dev/null || return 1
|
||||
grep '(tcpalso.no-questions/NS): nextitem' nextpart.out.${n} >/dev/null || return 1
|
||||
return 0
|
||||
}
|
||||
retry_quiet 12 check_namedrun || ret=1
|
||||
@@ -1015,5 +1015,14 @@ ttl=$(awk '{print $2}' dig.ns1.out.${n})
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "client requests recursion but it is disabled - expect EDE 20 code with REFUSED($n)"
|
||||
ret=0
|
||||
dig_with_opts +recurse www.isc.org @10.53.0.11 a >dig.out.ns11.test${n} || ret=1
|
||||
grep "status: REFUSED" dig.out.ns11.test${n} >/dev/null || ret=1
|
||||
grep -F "EDE: 20 (Not Authoritative)" dig.out.ns11.test${n} >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
||||
@@ -111,8 +111,8 @@ def test_rpz_passthru_logging():
|
||||
expected_rcode=dns.rcode.NOERROR,
|
||||
)
|
||||
assert res_allowed_any.answer == [
|
||||
dns.rrset.from_text("allowed.", 300, "IN", "NS", "ns1.allowed."),
|
||||
dns.rrset.from_text("allowed.", 300, "IN", "A", "10.53.0.2"),
|
||||
dns.rrset.from_text("allowed.", 300, "IN", "NS", "ns1.allowed."),
|
||||
]
|
||||
# The comparison above doesn't compare the TTL values, and we want to
|
||||
# make sure that the "passthru" rpz doesn't cap the TTL with max-policy-ttl.
|
||||
|
||||
@@ -115,10 +115,12 @@ sleep 2
|
||||
# stale for somewhere between 3500-3599 seconds.
|
||||
echo_i "check rndc dump stale data.example ($n)"
|
||||
rndc_dumpdb ns1 || ret=1
|
||||
awk '/; stale since [0-9]*/ { x=$0; getline; print x, $0}' ns1/named_dump.db.test$n \
|
||||
# add in inherited owner names
|
||||
awk '$1 ~ /^[0-9][0-9]*$/ { $0 = last " " $0 } $1 != ";" { last = $1 } { print }' ns1/named_dump.db.test$n >named_dump.db.test$n
|
||||
awk '/; stale since [0-9]*/ { x=$0; getline; print x, $0}' named_dump.db.test$n \
|
||||
| grep "; stale since [0-9]* data\.example.*3[56]...*TXT.*A text record with a 2 second ttl" >/dev/null 2>&1 || ret=1
|
||||
# Also make sure the not expired data does not have a stale comment.
|
||||
awk '/; authanswer/ { x=$0; getline; print x, $0}' ns1/named_dump.db.test$n \
|
||||
awk '/; authanswer/ { x=$0; getline; print x, $0}' named_dump.db.test$n \
|
||||
| grep "; authanswer longttl\.example.*[56]...*TXT.*A text record with a 600 second ttl" >/dev/null 2>&1 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
@@ -1664,16 +1666,15 @@ status=$((status + ret))
|
||||
# Check that expired records are dumped.
|
||||
echo_i "check rndc dump expired data.example ($n)"
|
||||
ret=0
|
||||
awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
|
||||
| grep "; expired (awaiting cleanup) data\.example\..*A text record with a 2 second ttl" >/dev/null 2>&1 || ret=1
|
||||
awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
|
||||
| grep "; expired (awaiting cleanup) nodata\.example\." >/dev/null 2>&1 || ret=1
|
||||
awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
|
||||
| grep "; expired (awaiting cleanup) nxdomain\.example\." >/dev/null 2>&1 || ret=1
|
||||
awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
|
||||
| grep "; expired (awaiting cleanup) othertype\.example\." >/dev/null 2>&1 || ret=1
|
||||
# add in inherited owner names
|
||||
awk '$1 ~ /^[0-9][0-9]*$/ { $0 = last " " $0 } $1 != ";" { last = $1 } { print }' ns5/named_dump.db.test$n >named_dump.db.test$n
|
||||
# extract expired records
|
||||
awk '/; expired/ { x=$0; getline; print x, $0}' named_dump.db.test$n >expired.test$n
|
||||
grep "; expired (awaiting cleanup) data\.example\..*A text record with a 2 second ttl" expired.test$n >/dev/null 2>&1 || ret=1
|
||||
grep "; expired (awaiting cleanup) nodata\.example\." expired.test$n >/dev/null 2>&1 || ret=1
|
||||
grep "; expired (awaiting cleanup) nxdomain\.example\." expired.test$n >/dev/null 2>&1 || ret=1
|
||||
# Also make sure the not expired data does not have an expired comment.
|
||||
awk '/; authanswer/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
|
||||
awk '/; authanswer/ { x=$0; getline; print x, $0}' named_dump.db.test$n \
|
||||
| grep "; authanswer longttl\.example.*A text record with a 600 second ttl" >/dev/null 2>&1 || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
@@ -14,6 +14,8 @@ import pytest
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"dig.out.*",
|
||||
"expired.test*",
|
||||
"named_dump.db.test*",
|
||||
"rndc.out.*",
|
||||
"ans*/ans.run",
|
||||
"ns*/named.stats*",
|
||||
|
||||
@@ -414,10 +414,10 @@ for ns in 2 4 5 6; do
|
||||
check_status NOERROR dig.out.ns${ns}.test$n || ret=1
|
||||
if [ ${synth} = yes ]; then
|
||||
check_synth_cname b.wild-cname.example. dig.out.ns${ns}.test$n || ret=1
|
||||
nextpart ns1/named.run | grep b.wild-cname.example/A >/dev/null && ret=1
|
||||
nextpart ns1/named.run | grep b.wild-cname.example/NS >/dev/null && ret=1
|
||||
else
|
||||
check_nosynth_cname b.wild-cname.example. dig.out.ns${ns}.test$n || ret=1
|
||||
nextpart ns1/named.run | grep b.wild-cname.example/A >/dev/null || ret=1
|
||||
nextpart ns1/named.run | grep b.wild-cname.example/NS >/dev/null || ret=1
|
||||
fi
|
||||
grep "ns1.example.*.IN.A" dig.out.ns${ns}.test$n >/dev/null || ret=1
|
||||
digcomp wildcname.out dig.out.ns${ns}.test$n || ret=1
|
||||
@@ -470,6 +470,7 @@ for ns in 2 4 5 6; do
|
||||
check_nosynth_aaaa b.wild-2-nsec-afterdata.example. dig.out.a.ns${ns}.test$n || ret=1
|
||||
#
|
||||
nextpart ns1/named.run >/dev/null
|
||||
sleep 1
|
||||
dig_with_opts b.wild-2-nsec-afterdata.example. @10.53.0.${ns} TLSA >dig.out.ns${ns}.test$n || ret=1
|
||||
check_ad_flag $ad dig.out.ns${ns}.test$n || ret=1
|
||||
check_status NOERROR dig.out.ns${ns}.test$n || ret=1
|
||||
@@ -531,7 +532,7 @@ for ns in 2 4 5 6; do
|
||||
check_ad_flag no dig.out.ns${ns}.test$n || ret=1
|
||||
check_status NOERROR dig.out.ns${ns}.test$n || ret=1
|
||||
check_nosynth_cname b.wild-cname.insecure.example dig.out.ns${ns}.test$n || ret=1
|
||||
nextpart ns1/named.run | grep b.wild-cname.insecure.example/A >/dev/null || ret=1
|
||||
nextpart ns1/named.run | grep b.wild-cname.insecure.example/NS >/dev/null || ret=1
|
||||
grep "ns1.insecure.example.*.IN.A" dig.out.ns${ns}.test$n >/dev/null || ret=1
|
||||
digcomp insecure.wildcname.out dig.out.ns${ns}.test$n || ret=1
|
||||
n=$((n + 1))
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
#
|
||||
m4_define([bind_VERSION_MAJOR], 9)dnl
|
||||
m4_define([bind_VERSION_MINOR], 21)dnl
|
||||
m4_define([bind_VERSION_PATCH], 6)dnl
|
||||
m4_define([bind_VERSION_PATCH], 7)dnl
|
||||
m4_define([bind_VERSION_EXTRA], -dev)dnl
|
||||
m4_define([bind_DESCRIPTION], [(Development Release)])dnl
|
||||
m4_define([bind_SRCID], [m4_esyscmd_s([git rev-parse --short HEAD | cut -b1-7])])dnl
|
||||
|
||||
@@ -3660,9 +3660,13 @@ system.
|
||||
after 20 minutes if it has remained unchanged.
|
||||
|
||||
If :any:`max-clients-per-query` is set to zero, there is no upper bound, other
|
||||
than that imposed by :any:`recursive-clients`. If :any:`clients-per-query` is
|
||||
set to zero, :any:`max-clients-per-query` no longer applies and there is no
|
||||
upper bound, other than that imposed by :any:`recursive-clients`.
|
||||
than that imposed by :any:`recursive-clients`. If the option is set to a
|
||||
lower value than :any:`clients-per-query`, the value is adjusted to
|
||||
:any:`clients-per-query`.
|
||||
|
||||
If :any:`clients-per-query` is set to zero, :any:`max-clients-per-query` no
|
||||
longer applies and there is no upper bound, other than that imposed by
|
||||
:any:`recursive-clients`.
|
||||
|
||||
.. namedconf:statement:: max-validations-per-fetch
|
||||
:tags: server
|
||||
|
||||
+2
-2
@@ -567,7 +567,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
||||
rdataset->ttl = ttlclamp(rdataset->ttl);
|
||||
}
|
||||
|
||||
REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
|
||||
REQUIRE(dns_rdatatype_isaddr(rdtype));
|
||||
|
||||
for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(rdataset))
|
||||
@@ -2557,7 +2557,7 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) {
|
||||
adb = adbname->adb;
|
||||
|
||||
REQUIRE(DNS_ADB_VALID(adb));
|
||||
REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
|
||||
REQUIRE(dns_rdatatype_isaddr(rdtype));
|
||||
|
||||
fname = dns_fixedname_initname(&foundname);
|
||||
dns_rdataset_init(&rdataset);
|
||||
|
||||
+1
-2
@@ -1516,8 +1516,7 @@ catz_process_primaries(dns_catz_zone_t *catz, dns_ipkeylist_t *ipkl,
|
||||
}
|
||||
/* else - 'simple' case - without labels */
|
||||
|
||||
if (value->type != dns_rdatatype_a && value->type != dns_rdatatype_aaaa)
|
||||
{
|
||||
if (!dns_rdatatype_isaddr(value->type)) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
+18
-12
@@ -1428,29 +1428,35 @@ addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, bool savekeys,
|
||||
|
||||
if (key != NULL) {
|
||||
/*
|
||||
* Found a match. If the old key was only public and the
|
||||
* new key is private, replace the old one; otherwise
|
||||
* leave it. But either way, mark the key as having
|
||||
* been found in the zone.
|
||||
* Found a match. If we already had a private key, then
|
||||
* the new key can't be an improvement. If the existing
|
||||
* key was public-only but the new key is too, then it's
|
||||
* still not an improvement. Mark the old key as having
|
||||
* been found in the zone and stop.
|
||||
*/
|
||||
if (dst_key_isprivate(key->key)) {
|
||||
dst_key_free(newkey);
|
||||
} else if (dst_key_isprivate(*newkey)) {
|
||||
dst_key_free(&key->key);
|
||||
key->key = *newkey;
|
||||
if (dst_key_isprivate(key->key) || !dst_key_isprivate(*newkey))
|
||||
{
|
||||
key->source = dns_keysource_zoneapex;
|
||||
return;
|
||||
}
|
||||
|
||||
key->source = dns_keysource_zoneapex;
|
||||
return;
|
||||
/*
|
||||
* However, if the old key was public-only, and the new key
|
||||
* is private, then we're throwing away the old key.
|
||||
*/
|
||||
dst_key_free(&key->key);
|
||||
ISC_LIST_UNLINK(*keylist, key, link);
|
||||
dns_dnsseckey_destroy(mctx, &key);
|
||||
}
|
||||
|
||||
/* Store the new key. */
|
||||
dns_dnsseckey_create(mctx, newkey, &key);
|
||||
key->source = dns_keysource_zoneapex;
|
||||
key->pubkey = pubkey_only;
|
||||
if (key->legacy || savekeys) {
|
||||
key->force_publish = true;
|
||||
key->force_sign = dst_key_isprivate(key->key);
|
||||
}
|
||||
key->source = dns_keysource_zoneapex;
|
||||
ISC_LIST_APPEND(*keylist, key, link);
|
||||
*newkey = NULL;
|
||||
}
|
||||
|
||||
@@ -205,9 +205,9 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
*\li Any other result indicates an error.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
bool
|
||||
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
dns_name_t *foundname, bool *wantdnssecp);
|
||||
dns_name_t *foundname);
|
||||
/*%<
|
||||
* Is 'name' at or beneath a trusted key?
|
||||
*
|
||||
@@ -219,20 +219,11 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
*
|
||||
*\li 'foundanme' is NULL or is a pointer to an initialized dns_name_t
|
||||
*
|
||||
*\li '*wantsdnssecp' is a valid bool.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
*\li On success, *wantsdnssecp will be true if and only if 'name'
|
||||
* is at or beneath a trusted key. If 'foundname' is not NULL, then
|
||||
* it will be updated to contain the name of the closest enclosing
|
||||
* trust anchor.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li ISC_R_SUCCESS
|
||||
*
|
||||
*\li Any other result is an error.
|
||||
*\li Returns true if and only if 'name' is at or beneath a trusted key.
|
||||
* If 'foundname' is not NULL, then it will be updated to contain
|
||||
* the name of the closest enclosing trust anchor.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
|
||||
@@ -54,26 +54,24 @@
|
||||
isc_result_t
|
||||
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
|
||||
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
|
||||
dns_ttl_t maxttl, dns_rdataset_t *addedrdataset);
|
||||
isc_result_t
|
||||
dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
|
||||
dns_dbnode_t *node, dns_rdatatype_t covers,
|
||||
isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
|
||||
bool optout, dns_rdataset_t *addedrdataset);
|
||||
dns_ttl_t maxttl, bool optout, bool secure,
|
||||
dns_rdataset_t *addedrdataset);
|
||||
/*%<
|
||||
* Convert the authority data from 'message' into a negative cache
|
||||
* rdataset, and store it in 'cache' at 'node' with a TTL limited to
|
||||
* 'maxttl'.
|
||||
*
|
||||
* \li dns_ncache_add produces a negative cache entry with a trust of no
|
||||
* more than answer
|
||||
* \li dns_ncache_addoptout produces a negative cache entry which will have
|
||||
* a trust of secure if all the records that make up the entry are secure.
|
||||
* \li If 'secure' is true and all the records that make up the entry
|
||||
* are secure, then dns_ncache_add produces a negative cache entry
|
||||
* with trust level secure.
|
||||
* \li If 'secure' is false, the negative cache entry's trust level
|
||||
* will be capped at answer.
|
||||
*
|
||||
* The 'covers' argument is the RR type whose nonexistence we are caching,
|
||||
* or dns_rdatatype_any when caching a NXDOMAIN response.
|
||||
*
|
||||
* 'optout' indicates a DNS_RDATASETATTR_OPTOUT should be set.
|
||||
* 'optout' indicates DNS_RDATASETATTR_OPTOUT should be set. This only
|
||||
* applies in secure zones; if 'secure' is false, 'optout' is ignored.
|
||||
*
|
||||
* Note:
|
||||
*\li If 'addedrdataset' is not NULL, then it will be attached to the added
|
||||
|
||||
+190
-117
@@ -113,6 +113,36 @@ struct dns_rdata {
|
||||
ISC_LINK(dns_rdata_t) link;
|
||||
};
|
||||
|
||||
/*%
|
||||
* Rdatatype attributes.
|
||||
*/
|
||||
enum {
|
||||
/*% only one may exist for a name */
|
||||
DNS_RDATATYPEATTR_SINGLETON = 1 << 0,
|
||||
/*% requires no other data be present */
|
||||
DNS_RDATATYPEATTR_EXCLUSIVE = 1 << 1,
|
||||
/*% Is a meta type */
|
||||
DNS_RDATATYPEATTR_META = 1 << 2,
|
||||
/*% Is a DNSSEC type, like RRSIG or NSEC */
|
||||
DNS_RDATATYPEATTR_DNSSEC = 1 << 3,
|
||||
/*% Is a zone cut authority type */
|
||||
DNS_RDATATYPEATTR_ZONECUTAUTH = 1 << 4,
|
||||
/*% Is reserved (unusable) */
|
||||
DNS_RDATATYPEATTR_RESERVED = 1 << 5,
|
||||
/*% Is an unknown type */
|
||||
DNS_RDATATYPEATTR_UNKNOWN = 1 << 6,
|
||||
/*% Is META, and can only be in a question section */
|
||||
DNS_RDATATYPEATTR_QUESTIONONLY = 1 << 7,
|
||||
/*% Is META, and can NOT be in a question section */
|
||||
DNS_RDATATYPEATTR_NOTQUESTION = 1 << 8,
|
||||
/*% Is present at zone cuts in the parent, not the child */
|
||||
DNS_RDATATYPEATTR_ATPARENT = 1 << 9,
|
||||
/*% Can exist along side a CNAME */
|
||||
DNS_RDATATYPEATTR_ATCNAME = 1 << 10,
|
||||
/*% Follow additional */
|
||||
DNS_RDATATYPEATTR_FOLLOWADDITIONAL = 1 << 11,
|
||||
};
|
||||
|
||||
#define DNS_RDATA_INIT \
|
||||
{ \
|
||||
.data = NULL, \
|
||||
@@ -530,16 +560,28 @@ dns_rdata_freestruct(void *source);
|
||||
* dns_rdata_tostruct().
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_rdatatype_ismeta(dns_rdatatype_t type);
|
||||
unsigned int
|
||||
dns_rdatatype_attributes(dns_rdatatype_t rdtype);
|
||||
/*%<
|
||||
* Return attributes for the given type.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'rdtype' are known.
|
||||
*
|
||||
* Returns:
|
||||
*\li a bitmask of the rdatatype attribute flags, defined above.
|
||||
*/
|
||||
|
||||
/*%
|
||||
* Return true iff the rdata type 'type' is a meta-type
|
||||
* like ANY or AXFR.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_ismeta(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_issingleton(dns_rdatatype_t type);
|
||||
/*%<
|
||||
/*%
|
||||
* Return true iff the rdata type 'type' is a singleton type,
|
||||
* like CNAME or SOA.
|
||||
*
|
||||
@@ -547,34 +589,108 @@ dns_rdatatype_issingleton(dns_rdatatype_t type);
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_issingleton(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON) !=
|
||||
0;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdataclass_ismeta(dns_rdataclass_t rdclass);
|
||||
/*%<
|
||||
* Return true iff the rdata class 'rdclass' is a meta-class
|
||||
* like ANY or NONE.
|
||||
/*%
|
||||
* Return true iff rdata of type 'type' can not appear in the question
|
||||
* section of a properly formatted message.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_notquestion(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) &
|
||||
DNS_RDATATYPEATTR_NOTQUESTION) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_isdnssec(dns_rdatatype_t type);
|
||||
/*%<
|
||||
/*%
|
||||
* Return true iff rdata of type 'type' can only appear in the question
|
||||
* section of a properly formatted message.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_questiononly(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) &
|
||||
DNS_RDATATYPEATTR_QUESTIONONLY) != 0;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff rdata of type 'type' can appear beside a cname.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_atcname(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATCNAME) !=
|
||||
0;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff rdata of type 'type' should appear at the parent of
|
||||
* a zone cut.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_atparent(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) !=
|
||||
0;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true if adding a record of type 'type' to the ADDITIONAL section
|
||||
* of a message can itself trigger the addition of still more data to the
|
||||
* additional section.
|
||||
*
|
||||
* (For example: adding SRV to the ADDITIONAL section may trigger
|
||||
* the addition of address records associated with that SRV.)
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_followadditional(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) &
|
||||
DNS_RDATATYPEATTR_FOLLOWADDITIONAL) != 0;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff 'type' is one of the DNSSEC
|
||||
* rdata types that may exist alongside a CNAME record.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_isdnssec(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_iskeymaterial(dns_rdatatype_t type);
|
||||
/*%<
|
||||
/*%
|
||||
* Return true iff the rdata type 'type' is a DNSSEC key
|
||||
* related type, like DNSKEY, CDNSKEY, or CDS.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_iskeymaterial(dns_rdatatype_t type) {
|
||||
return type == dns_rdatatype_dnskey || type == dns_rdatatype_cdnskey ||
|
||||
type == dns_rdatatype_cds;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_iszonecutauth(dns_rdatatype_t type);
|
||||
/*%<
|
||||
/*%
|
||||
* Return true iff rdata of type 'type' is considered authoritative
|
||||
* data (not glue) in the NSEC chain when it occurs in the parent zone
|
||||
* at a zone cut.
|
||||
@@ -583,16 +699,68 @@ dns_rdatatype_iszonecutauth(dns_rdatatype_t type);
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) &
|
||||
DNS_RDATATYPEATTR_ZONECUTAUTH) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_isknown(dns_rdatatype_t type);
|
||||
/*%<
|
||||
/*%
|
||||
* Return true iff the rdata type 'type' is known.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_isknown(dns_rdatatype_t type) {
|
||||
return (dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN) ==
|
||||
0;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff a query for the rdata type can have multiple
|
||||
* unrelated answers in a response: ANY, RRSIG, or SIG.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_ismulti(dns_rdatatype_t type) {
|
||||
return type == dns_rdatatype_any || type == dns_rdatatype_rrsig ||
|
||||
type == dns_rdatatype_sig;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff the rdata type is a signature: either RRSIG or SIG.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_issig(dns_rdatatype_t type) {
|
||||
return type == dns_rdatatype_rrsig || type == dns_rdatatype_sig;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff the rdata type is an address: either A or AAAA.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_isaddr(dns_rdatatype_t type) {
|
||||
return type == dns_rdatatype_a || type == dns_rdatatype_aaaa;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff the rdata type is an alias: either CNAME or DNAME.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdatatype_isalias(dns_rdatatype_t type) {
|
||||
return type == dns_rdatatype_cname || type == dns_rdatatype_dname;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Return true iff the rdata class 'rdclass' is a meta-class
|
||||
* like ANY or NONE.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
|
||||
return rdclass == dns_rdataclass_reserved0 ||
|
||||
rdclass == dns_rdataclass_none || rdclass == dns_rdataclass_any;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_rdata_additionaldata(dns_rdata_t *rdata, const dns_name_t *owner,
|
||||
@@ -653,101 +821,6 @@ dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg);
|
||||
*\li Many other results are possible if not successful.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_rdatatype_questiononly(dns_rdatatype_t type);
|
||||
/*%<
|
||||
* Return true iff rdata of type 'type' can only appear in the question
|
||||
* section of a properly formatted message.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_rdatatype_notquestion(dns_rdatatype_t type);
|
||||
/*%<
|
||||
* Return true iff rdata of type 'type' can not appear in the question
|
||||
* section of a properly formatted message.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_rdatatype_atparent(dns_rdatatype_t type);
|
||||
/*%<
|
||||
* Return true iff rdata of type 'type' should appear at the parent of
|
||||
* a zone cut.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_rdatatype_atcname(dns_rdatatype_t type);
|
||||
/*%<
|
||||
* Return true iff rdata of type 'type' can appear beside a cname.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_rdatatype_followadditional(dns_rdatatype_t type);
|
||||
/*%<
|
||||
* Return true if adding a record of type 'type' to the ADDITIONAL section
|
||||
* of a message can itself trigger the addition of still more data to the
|
||||
* additional section.
|
||||
*
|
||||
* (For example: adding SRV to the ADDITIONAL section may trigger
|
||||
* the addition of address records associated with that SRV.)
|
||||
*
|
||||
* Requires:
|
||||
* \li 'type' is a valid rdata type.
|
||||
*
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns_rdatatype_attributes(dns_rdatatype_t rdtype);
|
||||
/*%<
|
||||
* Return attributes for the given type.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'rdtype' are known.
|
||||
*
|
||||
* Returns:
|
||||
*\li a bitmask consisting of the following flags.
|
||||
*/
|
||||
|
||||
/*% only one may exist for a name */
|
||||
#define DNS_RDATATYPEATTR_SINGLETON 0x00000001U
|
||||
/*% requires no other data be present */
|
||||
#define DNS_RDATATYPEATTR_EXCLUSIVE 0x00000002U
|
||||
/*% Is a meta type */
|
||||
#define DNS_RDATATYPEATTR_META 0x00000004U
|
||||
/*% Is a DNSSEC type, like RRSIG or NSEC */
|
||||
#define DNS_RDATATYPEATTR_DNSSEC 0x00000008U
|
||||
/*% Is a zone cut authority type */
|
||||
#define DNS_RDATATYPEATTR_ZONECUTAUTH 0x00000010U
|
||||
/*% Is reserved (unusable) */
|
||||
#define DNS_RDATATYPEATTR_RESERVED 0x00000020U
|
||||
/*% Is an unknown type */
|
||||
#define DNS_RDATATYPEATTR_UNKNOWN 0x00000040U
|
||||
/*% Is META, and can only be in a question section */
|
||||
#define DNS_RDATATYPEATTR_QUESTIONONLY 0x00000080U
|
||||
/*% Is META, and can NOT be in a question section */
|
||||
#define DNS_RDATATYPEATTR_NOTQUESTION 0x00000100U
|
||||
/*% Is present at zone cuts in the parent, not the child */
|
||||
#define DNS_RDATATYPEATTR_ATPARENT 0x00000200U
|
||||
/*% Can exist along side a CNAME */
|
||||
#define DNS_RDATATYPEATTR_ATCNAME 0x00000400U
|
||||
/*% Follow additional */
|
||||
#define DNS_RDATATYPEATTR_FOLLOWADDITIONAL 0x00000800U
|
||||
|
||||
dns_rdatatype_t
|
||||
dns_rdata_covers(dns_rdata_t *rdata);
|
||||
/*%<
|
||||
|
||||
@@ -689,3 +689,30 @@ dns_rdataset_equals(const dns_rdataset_t *rdataset1,
|
||||
* \li 'rdataset1' is a valid rdataset.
|
||||
* \li 'rdataset2' is a valid rdataset.
|
||||
*/
|
||||
|
||||
/*%
|
||||
* Returns true if the rdataset is of type 'type', or type RRSIG
|
||||
* and covers 'type'.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdataset_matchestype(const dns_rdataset_t *rdataset,
|
||||
const dns_rdatatype_t type) {
|
||||
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||
|
||||
return rdataset->type == type ||
|
||||
(rdataset->type == dns_rdatatype_rrsig &&
|
||||
rdataset->covers == type);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Returns true if the rdataset is of type 'type', or type RRSIG
|
||||
* and covers 'type'.
|
||||
*/
|
||||
static inline bool
|
||||
dns_rdataset_issigtype(const dns_rdataset_t *rdataset,
|
||||
const dns_rdatatype_t type) {
|
||||
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||
|
||||
return rdataset->type == dns_rdatatype_rrsig &&
|
||||
rdataset->covers == type;
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ enum {
|
||||
* on ip6.arpa. */
|
||||
DNS_FETCHOPT_NOFORWARD = 1 << 15, /*%< Do not use forwarders if
|
||||
* possible. */
|
||||
DNS_FETCHOPT_QMINFETCH = 1 << 16, /*%< Qmin fetch */
|
||||
|
||||
/*% EDNS version bits: */
|
||||
DNS_FETCHOPT_EDNSVERSIONSET = 1 << 23,
|
||||
|
||||
@@ -986,13 +986,12 @@ dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp);
|
||||
*\li ISC_R_NOTFOUND
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
bool
|
||||
dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
|
||||
isc_stdtime_t now, bool checknta, bool *ntap,
|
||||
bool *secure_domain);
|
||||
isc_stdtime_t now, bool checknta, bool *ntap);
|
||||
/*%<
|
||||
* Is 'name' at or beneath a trusted key, and not covered by a valid
|
||||
* negative trust anchor? Put answer in '*secure_domain'.
|
||||
* negative trust anchor, and DNSSEC validation is enabled?
|
||||
*
|
||||
* If 'checknta' is false, ignore the NTA table in determining
|
||||
* whether this is a secure domain. If 'checknta' is not false, and if
|
||||
@@ -1001,10 +1000,6 @@ dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
|
||||
*
|
||||
* Requires:
|
||||
* \li 'view' is valid.
|
||||
*
|
||||
* Returns:
|
||||
*\li ISC_R_SUCCESS
|
||||
*\li Any other value indicates failure
|
||||
*/
|
||||
|
||||
bool
|
||||
|
||||
+40
-71
@@ -189,19 +189,13 @@ dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first) {
|
||||
isc_stdtime_t zrrsig_present;
|
||||
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
||||
zrrsig_present = published + ttlsig +
|
||||
dns_kasp_zonepropagationdelay(kasp);
|
||||
dns_kasp_zonepropagationdelay(kasp) +
|
||||
dns_kasp_publishsafety(kasp);
|
||||
if (zrrsig_present > syncpublish) {
|
||||
syncpublish = zrrsig_present;
|
||||
}
|
||||
}
|
||||
dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncpublish);
|
||||
|
||||
uint32_t lifetime = 0;
|
||||
ret = dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
|
||||
if (ret == ISC_R_SUCCESS && lifetime > 0) {
|
||||
dst_key_settime(key, DST_TIME_SYNCDELETE,
|
||||
(syncpublish + lifetime));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -249,17 +243,6 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
pub = now;
|
||||
}
|
||||
|
||||
/*
|
||||
* To calculate phase out times ("Retired", "Removed", ...),
|
||||
* the key lifetime is required.
|
||||
*/
|
||||
uint32_t klifetime = 0;
|
||||
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
|
||||
klifetime = lifetime;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate prepublication time.
|
||||
*/
|
||||
@@ -289,16 +272,13 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp,
|
||||
true);
|
||||
syncpub2 = pub + ttlsig +
|
||||
dns_kasp_publishsafety(kasp) +
|
||||
dns_kasp_zonepropagationdelay(kasp);
|
||||
}
|
||||
|
||||
syncpub = ISC_MAX(syncpub1, syncpub2);
|
||||
dst_key_settime(key->key, DST_TIME_SYNCPUBLISH,
|
||||
syncpub);
|
||||
if (klifetime > 0) {
|
||||
dst_key_settime(key->key, DST_TIME_SYNCDELETE,
|
||||
(syncpub + klifetime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +291,13 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
|
||||
ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
uint32_t klifetime = 0;
|
||||
|
||||
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
|
||||
klifetime = lifetime;
|
||||
}
|
||||
if (klifetime == 0) {
|
||||
/*
|
||||
* No inactive time and no lifetime,
|
||||
@@ -411,7 +398,7 @@ keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
/* Initialize lifetime. */
|
||||
if (r != ISC_R_SUCCESS) {
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
|
||||
l = lifetime - 1;
|
||||
return;
|
||||
}
|
||||
/* Skip keys that are still hidden or already retiring. */
|
||||
if (g != OMNIPRESENT) {
|
||||
@@ -433,7 +420,6 @@ keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
} else {
|
||||
dst_key_unsettime(key->key, DST_TIME_INACTIVE);
|
||||
dst_key_unsettime(key->key, DST_TIME_DELETE);
|
||||
dst_key_unsettime(key->key, DST_TIME_SYNCDELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1300,7 +1286,6 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t lastchange, dstime, nexttime = now;
|
||||
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
||||
uint32_t dsstate;
|
||||
|
||||
/*
|
||||
* No need to wait if we move things into an uncertain state.
|
||||
@@ -1370,12 +1355,15 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
* records. This translates to:
|
||||
*
|
||||
* Dsgn + zone-propagation-delay + max-zone-ttl.
|
||||
*
|
||||
* We will also add the retire-safety interval.
|
||||
*/
|
||||
nexttime = lastchange + ttlsig +
|
||||
dns_kasp_zonepropagationdelay(kasp);
|
||||
dns_kasp_zonepropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
/*
|
||||
* Only add the sign delay Dsgn and retire-safety if
|
||||
* there is an actual predecessor or successor key.
|
||||
* Only add the sign delay Dsgn if there is an actual
|
||||
* predecessor or successor key.
|
||||
*/
|
||||
uint32_t tag;
|
||||
ret = dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
|
||||
@@ -1385,8 +1373,7 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
DST_NUM_SUCCESSOR, &tag);
|
||||
}
|
||||
if (ret == ISC_R_SUCCESS) {
|
||||
nexttime += dns_kasp_signdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
nexttime += dns_kasp_signdelay(kasp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1412,36 +1399,35 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
* This translates to:
|
||||
*
|
||||
* parent-propagation-delay + parent-ds-ttl.
|
||||
*
|
||||
* We will also add the retire-safety interval.
|
||||
*/
|
||||
case OMNIPRESENT:
|
||||
case HIDDEN:
|
||||
/* Make sure DS has been seen in/withdrawn from the
|
||||
* parent. */
|
||||
dsstate = next_state == HIDDEN ? DST_TIME_DSDELETE
|
||||
: DST_TIME_DSPUBLISH;
|
||||
ret = dst_key_gettime(key->key, dsstate, &dstime);
|
||||
/* Make sure DS has been seen in the parent. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_DSPUBLISH,
|
||||
&dstime);
|
||||
if (ret != ISC_R_SUCCESS || dstime > now) {
|
||||
/* Not yet, try again in an hour. */
|
||||
nexttime = now + 3600;
|
||||
} else {
|
||||
nexttime =
|
||||
dstime + dns_kasp_dsttl(kasp) +
|
||||
dns_kasp_parentpropagationdelay(kasp);
|
||||
/*
|
||||
* Only add the retire-safety if there is an
|
||||
* actual predecessor or successor key.
|
||||
*/
|
||||
uint32_t tag;
|
||||
ret = dst_key_getnum(key->key,
|
||||
DST_NUM_PREDECESSOR, &tag);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
ret = dst_key_getnum(key->key,
|
||||
DST_NUM_SUCCESSOR,
|
||||
&tag);
|
||||
}
|
||||
if (ret == ISC_R_SUCCESS) {
|
||||
nexttime += dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
dns_kasp_parentpropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
break;
|
||||
case HIDDEN:
|
||||
/* Make sure DS has been withdrawn from the parent. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_DSDELETE,
|
||||
&dstime);
|
||||
if (ret != ISC_R_SUCCESS || dstime > now) {
|
||||
/* Not yet, try again in an hour. */
|
||||
nexttime = now + 3600;
|
||||
} else {
|
||||
nexttime =
|
||||
dstime + dns_kasp_dsttl(kasp) +
|
||||
dns_kasp_parentpropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1777,9 +1763,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
||||
if (prepub == 0 || prepub > now) {
|
||||
/* No need to start rollover now. */
|
||||
if (*nexttime == 0 || prepub < *nexttime) {
|
||||
if (prepub > 0) {
|
||||
*nexttime = prepub;
|
||||
}
|
||||
*nexttime = prepub;
|
||||
}
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
@@ -2038,20 +2022,6 @@ keymgr_purge_keyfile(dst_key_t *key, int type) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
dst_key_doublematch(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
|
||||
int matches = 0;
|
||||
|
||||
for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
if (dns_kasp_key_match(kkey, key)) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
return matches > 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine 'keys' and match 'kasp' policy.
|
||||
*
|
||||
@@ -2191,7 +2161,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
* matches the kasp policy.
|
||||
*/
|
||||
if (!dst_key_is_unused(dkey->key) &&
|
||||
!dst_key_doublematch(dkey, kasp) &&
|
||||
(dst_key_goal(dkey->key) ==
|
||||
OMNIPRESENT) &&
|
||||
!keymgr_dep(dkey->key, keyring,
|
||||
|
||||
+5
-9
@@ -530,13 +530,14 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
return result;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
bool
|
||||
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
dns_name_t *foundname, bool *wantdnssecp) {
|
||||
dns_name_t *foundname) {
|
||||
isc_result_t result;
|
||||
dns_qpread_t qpr;
|
||||
dns_keynode_t *keynode = NULL;
|
||||
void *pval = NULL;
|
||||
bool secure = false;
|
||||
|
||||
/*
|
||||
* Is 'name' at or beneath a trusted key?
|
||||
@@ -544,7 +545,6 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
|
||||
REQUIRE(VALID_KEYTABLE(keytable));
|
||||
REQUIRE(dns_name_isabsolute(name));
|
||||
REQUIRE(wantdnssecp != NULL);
|
||||
|
||||
dns_qpmulti_query(keytable->table, &qpr);
|
||||
result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, &pval, NULL);
|
||||
@@ -553,16 +553,12 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
|
||||
if (foundname != NULL) {
|
||||
dns_name_copy(&keynode->name, foundname);
|
||||
}
|
||||
*wantdnssecp = true;
|
||||
result = ISC_R_SUCCESS;
|
||||
} else if (result == ISC_R_NOTFOUND) {
|
||||
*wantdnssecp = false;
|
||||
result = ISC_R_SUCCESS;
|
||||
secure = true;
|
||||
}
|
||||
|
||||
dns_qpread_destroy(keytable->table, &qpr);
|
||||
|
||||
return result;
|
||||
return secure;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
||||
+1
-1
@@ -1914,7 +1914,7 @@ load_text(dns_loadctx_t *lctx) {
|
||||
}
|
||||
}
|
||||
|
||||
if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) {
|
||||
if (dns_rdatatype_issig(type)) {
|
||||
covers = dns_rdata_covers(&rdata[rdcount]);
|
||||
} else {
|
||||
covers = 0;
|
||||
|
||||
+7
-27
@@ -50,12 +50,6 @@ atomic_getuint8(isc_buffer_t *b) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
|
||||
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
|
||||
dns_ttl_t maxttl, bool optout, bool secure,
|
||||
dns_rdataset_t *addedrdataset);
|
||||
|
||||
static isc_result_t
|
||||
copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
|
||||
isc_result_t result;
|
||||
@@ -107,25 +101,8 @@ copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
|
||||
isc_result_t
|
||||
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
|
||||
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
|
||||
dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) {
|
||||
return addoptout(message, cache, node, covers, now, minttl, maxttl,
|
||||
false, false, addedrdataset);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
|
||||
dns_dbnode_t *node, dns_rdatatype_t covers,
|
||||
isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
|
||||
bool optout, dns_rdataset_t *addedrdataset) {
|
||||
return addoptout(message, cache, node, covers, now, minttl, maxttl,
|
||||
optout, true, addedrdataset);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
|
||||
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
|
||||
dns_ttl_t maxttl, bool optout, bool secure,
|
||||
dns_rdataset_t *addedrdataset) {
|
||||
dns_ttl_t maxttl, bool optout, bool secure,
|
||||
dns_rdataset_t *addedrdataset) {
|
||||
isc_result_t result;
|
||||
isc_buffer_t buffer;
|
||||
isc_region_t r;
|
||||
@@ -143,14 +120,17 @@ addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
|
||||
/*
|
||||
* Convert the authority data from 'message' into a negative cache
|
||||
* rdataset, and store it in 'cache' at 'node'.
|
||||
*
|
||||
* We assume that all data in the authority section has been
|
||||
* validated by the caller.
|
||||
*/
|
||||
|
||||
REQUIRE(message != NULL);
|
||||
|
||||
/*
|
||||
* We assume that all data in the authority section has been
|
||||
* validated by the caller.
|
||||
* If 'secure' is false, ignore 'optout'.
|
||||
*/
|
||||
optout = optout && secure;
|
||||
|
||||
/*
|
||||
* Initialize the list.
|
||||
|
||||
+1
-2
@@ -513,8 +513,7 @@ need_headerupdate(dns_slabheader_t *header, isc_stdtime_t now) {
|
||||
#if DNS_QPDB_LIMITLRUUPDATE
|
||||
if (header->type == dns_rdatatype_ns ||
|
||||
(header->trust == dns_trust_glue &&
|
||||
(header->type == dns_rdatatype_a ||
|
||||
header->type == dns_rdatatype_aaaa)))
|
||||
dns_rdatatype_isaddr(header->type)))
|
||||
{
|
||||
/*
|
||||
* Glue records are updated if at least DNS_QPDB_LRUUPDATE_GLUE
|
||||
|
||||
+16
-4
@@ -2696,13 +2696,25 @@ step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction,
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
|
||||
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
||||
dns_slabheader_t *header_next = NULL;
|
||||
|
||||
NODE_RDLOCK(nlock, &nlocktype);
|
||||
for (header = node->data; header != NULL; header = header->next)
|
||||
for (header = node->data; header != NULL; header = header_next)
|
||||
{
|
||||
if (header->serial <= search->serial &&
|
||||
!IGNORE(header) && !NONEXISTENT(header))
|
||||
{
|
||||
header_next = header->next;
|
||||
while (header != NULL) {
|
||||
if (header->serial <= search->serial &&
|
||||
!IGNORE(header))
|
||||
{
|
||||
if (NONEXISTENT(header)) {
|
||||
header = NULL;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
header = header->down;
|
||||
}
|
||||
}
|
||||
if (header != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
-107
@@ -2354,113 +2354,6 @@ dns_rdata_covers(dns_rdata_t *rdata) {
|
||||
return covers_sig(rdata);
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_ismeta(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_issingleton(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_notquestion(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION) !=
|
||||
0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_questiononly(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY) !=
|
||||
0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_atcname(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATCNAME) != 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_atparent(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_followadditional(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) &
|
||||
DNS_RDATATYPEATTR_FOLLOWADDITIONAL) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
|
||||
if (rdclass == dns_rdataclass_reserved0 ||
|
||||
rdclass == dns_rdataclass_none || rdclass == dns_rdataclass_any)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; /* Assume it is not a meta class. */
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_isdnssec(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_iskeymaterial(dns_rdatatype_t type) {
|
||||
return type == dns_rdatatype_dnskey || type == dns_rdatatype_cdnskey ||
|
||||
type == dns_rdatatype_cds;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ZONECUTAUTH) !=
|
||||
0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_rdatatype_isknown(dns_rdatatype_t type) {
|
||||
if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type) {
|
||||
REQUIRE(rdata != NULL);
|
||||
|
||||
+1047
-1271
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -752,7 +752,7 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||
UNUSED(now);
|
||||
UNUSED(sigrdataset);
|
||||
|
||||
if (type == dns_rdatatype_sig || type == dns_rdatatype_rrsig) {
|
||||
if (dns_rdatatype_issig(type)) {
|
||||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
+38
-20
@@ -182,6 +182,9 @@ expire_rdatasets(dns_validator_t *val) {
|
||||
static void
|
||||
validate_extendederror(dns_validator_t *val);
|
||||
|
||||
static void
|
||||
validator_addede(dns_validator_t *val, uint16_t code, const char *extra);
|
||||
|
||||
/*%
|
||||
* Ensure the validator's rdatasets are disassociated.
|
||||
*/
|
||||
@@ -1474,6 +1477,11 @@ again:
|
||||
* Temporal errors don't count towards max validations nor max
|
||||
* fails.
|
||||
*/
|
||||
validator_addede(val,
|
||||
result == DNS_R_SIGEXPIRED
|
||||
? DNS_EDE_SIGNATUREEXPIRED
|
||||
: DNS_EDE_SIGNATURENOTYETVALID,
|
||||
NULL);
|
||||
break;
|
||||
case ISC_R_SUCCESS:
|
||||
consume_validation(val);
|
||||
@@ -3627,44 +3635,54 @@ validator_logcreate(dns_validator_t *val, dns_name_t *name,
|
||||
}
|
||||
|
||||
static void
|
||||
validate_extendederror(dns_validator_t *val) {
|
||||
validator_addede(dns_validator_t *val, uint16_t code, const char *extra) {
|
||||
REQUIRE(VALID_VALIDATOR(val));
|
||||
|
||||
char extra[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE +
|
||||
char bdata[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE +
|
||||
DNS_EDE_EXTRATEXT_LEN];
|
||||
isc_buffer_t b;
|
||||
|
||||
isc_buffer_init(&b, bdata, sizeof(bdata));
|
||||
|
||||
if (extra != NULL) {
|
||||
isc_buffer_putstr(&b, extra);
|
||||
isc_buffer_putuint8(&b, ' ');
|
||||
}
|
||||
|
||||
dns_name_totext(val->name, DNS_NAME_OMITFINALDOT, &b);
|
||||
isc_buffer_putuint8(&b, '/');
|
||||
dns_rdatatype_totext(val->type, &b);
|
||||
isc_buffer_putuint8(&b, '\0');
|
||||
|
||||
dns_ede_add(val->edectx, code, bdata);
|
||||
}
|
||||
|
||||
static void
|
||||
validate_extendederror(dns_validator_t *val) {
|
||||
dns_validator_t *edeval = val;
|
||||
char bdata[DNS_EDE_EXTRATEXT_LEN];
|
||||
isc_buffer_t b;
|
||||
|
||||
REQUIRE(VALID_VALIDATOR(edeval));
|
||||
|
||||
isc_buffer_init(&b, bdata, sizeof(bdata));
|
||||
|
||||
while (edeval->parent != NULL) {
|
||||
edeval = edeval->parent;
|
||||
}
|
||||
|
||||
if (val->unsupported_algorithm != 0) {
|
||||
isc_buffer_init(&b, extra, sizeof(extra));
|
||||
isc_buffer_clear(&b);
|
||||
dns_secalg_totext(val->unsupported_algorithm, &b);
|
||||
|
||||
isc_buffer_putuint8(&b, ' ');
|
||||
dns_name_totext(val->name, DNS_NAME_OMITFINALDOT, &b);
|
||||
isc_buffer_putuint8(&b, '/');
|
||||
dns_rdatatype_totext(val->type, &b);
|
||||
isc_buffer_putuint8(&b, '\0');
|
||||
|
||||
dns_ede_add(val->edectx, DNS_EDE_DNSKEYALG, extra);
|
||||
validator_addede(val, DNS_EDE_DNSKEYALG, bdata);
|
||||
}
|
||||
|
||||
if (val->unsupported_digest != 0) {
|
||||
isc_buffer_init(&b, extra, sizeof(extra));
|
||||
|
||||
isc_buffer_clear(&b);
|
||||
dns_dsdigest_totext(val->unsupported_digest, &b);
|
||||
isc_buffer_putuint8(&b, ' ');
|
||||
dns_name_totext(val->name, DNS_NAME_OMITFINALDOT, &b);
|
||||
isc_buffer_putuint8(&b, '/');
|
||||
dns_rdatatype_totext(val->type, &b);
|
||||
isc_buffer_putuint8(&b, '\0');
|
||||
|
||||
dns_ede_add(val->edectx, DNS_EDE_DSDIGESTTYPE, extra);
|
||||
|
||||
isc_buffer_invalidate(&b);
|
||||
validator_addede(val, DNS_EDE_DSDIGESTTYPE, bdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-17
@@ -1533,41 +1533,31 @@ dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now, const dns_name_t *name,
|
||||
return dns_ntatable_covered(view->ntatable_priv, now, name, anchor);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
bool
|
||||
dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
|
||||
isc_stdtime_t now, bool checknta, bool *ntap,
|
||||
bool *secure_domain) {
|
||||
isc_result_t result;
|
||||
isc_stdtime_t now, bool checknta, bool *ntap) {
|
||||
bool secure = false;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *anchor;
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
if (view->secroots_priv == NULL) {
|
||||
return ISC_R_NOTFOUND;
|
||||
if (!view->enablevalidation || view->secroots_priv == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
anchor = dns_fixedname_initname(&fn);
|
||||
|
||||
result = dns_keytable_issecuredomain(view->secroots_priv, name, anchor,
|
||||
&secure);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
secure = dns_keytable_issecuredomain(view->secroots_priv, name, anchor);
|
||||
|
||||
SET_IF_NOT_NULL(ntap, false);
|
||||
if (checknta && secure && view->ntatable_priv != NULL &&
|
||||
dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
|
||||
{
|
||||
if (ntap != NULL) {
|
||||
*ntap = true;
|
||||
}
|
||||
SET_IF_NOT_NULL(ntap, true);
|
||||
secure = false;
|
||||
}
|
||||
|
||||
*secure_domain = secure;
|
||||
return ISC_R_SUCCESS;
|
||||
return secure;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+13
-25
@@ -3318,9 +3318,7 @@ rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
|
||||
}
|
||||
dns_db_detachnode(*dbp, nodep);
|
||||
|
||||
if (qtype == dns_rdatatype_rrsig ||
|
||||
qtype == dns_rdatatype_sig)
|
||||
{
|
||||
if (dns_rdatatype_issig(qtype)) {
|
||||
result = DNS_R_NXRRSET;
|
||||
} else {
|
||||
result = dns_db_findext(*dbp, p_name, *versionp,
|
||||
@@ -5044,9 +5042,7 @@ qctx_init(ns_client_t *client, dns_fetchresponse_t **frespp,
|
||||
/*
|
||||
* If it's an RRSIG or SIG query, we'll iterate the node.
|
||||
*/
|
||||
if (qctx->qtype == dns_rdatatype_rrsig ||
|
||||
qctx->qtype == dns_rdatatype_sig)
|
||||
{
|
||||
if (dns_rdatatype_issig(qctx->qtype)) {
|
||||
qctx->type = dns_rdatatype_any;
|
||||
}
|
||||
|
||||
@@ -5439,8 +5435,7 @@ ns__query_start(query_ctx_t *qctx) {
|
||||
*/
|
||||
if (qctx->view->root_key_sentinel &&
|
||||
qctx->client->query.restarts == 0 &&
|
||||
(qctx->qtype == dns_rdatatype_a ||
|
||||
qctx->qtype == dns_rdatatype_aaaa) &&
|
||||
(dns_rdatatype_isaddr(qctx->qtype)) &&
|
||||
(qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
|
||||
{
|
||||
root_key_sentinel_detect(qctx);
|
||||
@@ -5525,6 +5520,9 @@ ns__query_start(query_ctx_t *qctx) {
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (result == DNS_R_REFUSED) {
|
||||
if (WANTRECURSION(qctx->client)) {
|
||||
dns_ede_add(&qctx->client->edectx,
|
||||
DNS_EDE_NOTAUTH,
|
||||
"recursion disabled");
|
||||
inc_stats(qctx->client,
|
||||
ns_statscounter_recurserej);
|
||||
} else {
|
||||
@@ -6492,9 +6490,7 @@ query_resume(query_ctx_t *qctx) {
|
||||
}
|
||||
INSIST(qctx->rdataset != NULL);
|
||||
|
||||
if (qctx->qtype == dns_rdatatype_rrsig ||
|
||||
qctx->qtype == dns_rdatatype_sig)
|
||||
{
|
||||
if (dns_rdatatype_issig(qctx->qtype)) {
|
||||
qctx->type = dns_rdatatype_any;
|
||||
} else {
|
||||
qctx->type = qctx->qtype;
|
||||
@@ -7732,8 +7728,7 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
|
||||
!WANTDNSSEC(qctx->client) &&
|
||||
qctx->qtype == dns_rdatatype_any &&
|
||||
(qctx->rdataset->type == dns_rdatatype_sig ||
|
||||
qctx->rdataset->type == dns_rdatatype_rrsig))
|
||||
(dns_rdatatype_issig(qctx->rdataset->type)))
|
||||
{
|
||||
CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
|
||||
"minimal-any skip signature");
|
||||
@@ -7778,9 +7773,7 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
* Remember the first RRtype we find so we
|
||||
* can skip others with minimal-any.
|
||||
*/
|
||||
if (qctx->rdataset->type == dns_rdatatype_sig ||
|
||||
qctx->rdataset->type == dns_rdatatype_rrsig)
|
||||
{
|
||||
if (dns_rdatatype_issig(qctx->rdataset->type)) {
|
||||
onetype = qctx->rdataset->covers;
|
||||
} else {
|
||||
onetype = qctx->rdataset->type;
|
||||
@@ -7844,9 +7837,7 @@ query_respond_any(query_ctx_t *qctx) {
|
||||
* At least one matching rdataset was found
|
||||
*/
|
||||
query_addauth(qctx);
|
||||
} else if (qctx->qtype == dns_rdatatype_rrsig ||
|
||||
qctx->qtype == dns_rdatatype_sig)
|
||||
{
|
||||
} else if (dns_rdatatype_issig(qctx->qtype)) {
|
||||
/*
|
||||
* No matching rdatasets were found, but we got
|
||||
* here on a search for RRSIG/SIG, so that's okay.
|
||||
@@ -9915,8 +9906,7 @@ query_coveringnsec(query_ctx_t *qctx) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
|
||||
(qctx->type == dns_rdatatype_a ||
|
||||
qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
|
||||
dns_rdatatype_isaddr(qctx->type)) /* XXX not yet */
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -9975,8 +9965,7 @@ query_coveringnsec(query_ctx_t *qctx) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
|
||||
(qctx->type == dns_rdatatype_a ||
|
||||
qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
|
||||
dns_rdatatype_isaddr(qctx->type)) /* XXX not yet */
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -11326,8 +11315,7 @@ query_glueanswer(query_ctx_t *qctx) {
|
||||
|
||||
if (!ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
|
||||
qctx->client->message->rcode != dns_rcode_noerror ||
|
||||
(qctx->qtype != dns_rdatatype_a &&
|
||||
qctx->qtype != dns_rdatatype_aaaa))
|
||||
!dns_rdatatype_isaddr(qctx->qtype))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-3
@@ -1165,9 +1165,7 @@ temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
|
||||
* this name and type */
|
||||
|
||||
*typep = type = t->rdata.type;
|
||||
if (type == dns_rdatatype_rrsig ||
|
||||
type == dns_rdatatype_sig)
|
||||
{
|
||||
if (dns_rdatatype_issig(type)) {
|
||||
covers = dns_rdata_covers(&t->rdata);
|
||||
} else if (type == dns_rdatatype_any) {
|
||||
dns_db_detachnode(db, &node);
|
||||
|
||||
+2
-6
@@ -135,9 +135,7 @@ log_rr(dns_name_t *name, dns_rdata_t *rdata, uint32_t ttl) {
|
||||
rdl.type = rdata->type;
|
||||
rdl.rdclass = rdata->rdclass;
|
||||
rdl.ttl = ttl;
|
||||
if (rdata->type == dns_rdatatype_sig ||
|
||||
rdata->type == dns_rdatatype_rrsig)
|
||||
{
|
||||
if (dns_rdatatype_issig(rdata->type)) {
|
||||
rdl.covers = dns_rdata_covers(rdata);
|
||||
} else {
|
||||
rdl.covers = dns_rdatatype_none;
|
||||
@@ -1553,9 +1551,7 @@ sendstream(xfrout_ctx_t *xfr) {
|
||||
msgrdl->type = rdata->type;
|
||||
msgrdl->rdclass = rdata->rdclass;
|
||||
msgrdl->ttl = ttl;
|
||||
if (rdata->type == dns_rdatatype_sig ||
|
||||
rdata->type == dns_rdatatype_rrsig)
|
||||
{
|
||||
if (dns_rdatatype_issig(rdata->type)) {
|
||||
msgrdl->covers = dns_rdata_covers(rdata);
|
||||
} else {
|
||||
msgrdl->covers = dns_rdatatype_none;
|
||||
|
||||
+33
-1
@@ -351,8 +351,40 @@ ISC_LOOP_TEST_IMPL(version) {
|
||||
result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
|
||||
foundname, &rdataset, NULL);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
dns_db_detachnode(db, &node);
|
||||
|
||||
/* Now we create a node with an empty parent */
|
||||
result = dns_db_newversion(db, &new);
|
||||
dns_test_namefromstring("long.ent.name.test.test.", &fname);
|
||||
result = dns_db_findnode(db, name, true, &node);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
result = dns_db_addrdataset(db, node, new, 0, &rdataset, 0, NULL);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
dns_rdataset_init(&rdataset);
|
||||
|
||||
/* look up the ENT; it should be empty */
|
||||
dns_test_namefromstring("ent.name.test.test.", &fname);
|
||||
dns_db_detachnode(db, &node);
|
||||
result = dns_db_find(db, name, new, dns_rdatatype_a, 0, 0, &node,
|
||||
foundname, &rdataset, NULL);
|
||||
assert_int_equal(result, DNS_R_EMPTYNAME);
|
||||
|
||||
/* ... but then we roll it back... */
|
||||
dns_db_closeversion(db, &new, false);
|
||||
|
||||
/* ... and the ENT should be NXDOMAIN now */
|
||||
dns_test_namefromstring("ent.name.test.test.", &fname);
|
||||
result = dns_db_find(db, name, ver, dns_rdatatype_a, 0, 0, &node,
|
||||
foundname, &rdataset, NULL);
|
||||
assert_int_equal(result, DNS_R_NXDOMAIN);
|
||||
|
||||
if (dns_rdataset_isassociated(&rdataset)) {
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
}
|
||||
if (node != NULL) {
|
||||
dns_db_detachnode(db, &node);
|
||||
}
|
||||
dns_db_closeversion(db, &ver, false);
|
||||
|
||||
dns_db_detach(&db);
|
||||
|
||||
@@ -363,6 +363,154 @@ ISC_RUN_TEST_IMPL(getnsec3parameters) {
|
||||
db1, v2, &hash, &flags, &iterations, salt, &salt_length));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the correct node contents are found after a rollback.
|
||||
*/
|
||||
ISC_RUN_TEST_IMPL(rollback) {
|
||||
isc_result_t res;
|
||||
dns_rdata_t rdata1 = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT;
|
||||
dns_rdataset_t input1 = DNS_RDATASET_INIT;
|
||||
dns_rdataset_t input2 = DNS_RDATASET_INIT;
|
||||
dns_rdataset_t rdataset1 = DNS_RDATASET_INIT;
|
||||
dns_rdataset_t rdataset2 = DNS_RDATASET_INIT;
|
||||
dns_rdatalist_t rdatalist1, rdatalist2;
|
||||
dns_rdata_t out1 = DNS_RDATA_INIT, out2 = DNS_RDATA_INIT;
|
||||
dns_dbnode_t *node = NULL;
|
||||
char *txt1 = (char *)"\006text 1";
|
||||
char *txt2 = (char *)"\006text 2";
|
||||
size_t len1 = strlen(txt1), len2 = strlen(txt2);
|
||||
char buf[1024];
|
||||
isc_buffer_t b;
|
||||
|
||||
UNUSED(state);
|
||||
|
||||
isc_buffer_init(&b, buf, sizeof(buf));
|
||||
|
||||
/* Set up two rdatasets to insert */
|
||||
rdata1.rdclass = dns_rdataclass_in;
|
||||
rdata1.type = dns_rdatatype_txt;
|
||||
rdata2 = rdata1;
|
||||
|
||||
rdata1.length = len1;
|
||||
rdata1.data = (unsigned char *)txt1;
|
||||
rdata2.length = len2;
|
||||
rdata2.data = (unsigned char *)txt2;
|
||||
|
||||
dns_rdatalist_init(&rdatalist1);
|
||||
rdatalist1.rdclass = dns_rdataclass_in;
|
||||
rdatalist1.type = dns_rdatatype_txt;
|
||||
rdatalist1.ttl = 3600;
|
||||
rdatalist2 = rdatalist1;
|
||||
|
||||
ISC_LIST_APPEND(rdatalist1.rdata, &rdata1, link);
|
||||
ISC_LIST_APPEND(rdatalist2.rdata, &rdata2, link);
|
||||
|
||||
dns_rdatalist_tordataset(&rdatalist1, &input1);
|
||||
dns_rdatalist_tordataset(&rdatalist2, &input2);
|
||||
|
||||
/* db1: Insert the first version ("text 1"), and commit */
|
||||
res = dns_db_findnode(db1, dns_rootname, true, &node);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
res = dns_db_addrdataset(db1, node, v1, 0, &input1, 0, NULL);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
dns_db_closeversion(db1, &v1, true); /* commit */
|
||||
assert_null(v1);
|
||||
dns_db_detachnode(db1, &node);
|
||||
assert_null(node);
|
||||
|
||||
/* db2: Insert the first version ("text 1"), and commit */
|
||||
res = dns_db_findnode(db2, dns_rootname, true, &node);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
res = dns_db_addrdataset(db2, node, v2, 0, &input1, 0, NULL);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
dns_db_closeversion(db2, &v2, true); /* commit */
|
||||
assert_null(v2);
|
||||
dns_db_detachnode(db2, &node);
|
||||
assert_null(node);
|
||||
|
||||
/* Reopen the versions */
|
||||
dns_db_newversion(db1, &v1);
|
||||
assert_non_null(v1);
|
||||
dns_db_newversion(db2, &v2);
|
||||
assert_non_null(v2);
|
||||
|
||||
/* db1: Insert the second version ("text 2"), and roll back */
|
||||
res = dns_db_findnode(db1, dns_rootname, true, &node);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
res = dns_db_addrdataset(db1, node, v1, 0, &input2, 0, NULL);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
dns_db_closeversion(db1, &v1, false); /* rollback */
|
||||
assert_null(v1);
|
||||
dns_db_detachnode(db1, &node);
|
||||
assert_null(node);
|
||||
|
||||
/* db2: Insert the second version ("text 2"), and commit */
|
||||
res = dns_db_findnode(db2, dns_rootname, true, &node);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
res = dns_db_addrdataset(db2, node, v2, 0, &input2, 0, NULL);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
dns_db_closeversion(db2, &v2, true); /* commit */
|
||||
assert_null(v2);
|
||||
dns_db_detachnode(db2, &node);
|
||||
assert_null(node);
|
||||
|
||||
/* db1: Look it up and check that the first version is found */
|
||||
dns_db_currentversion(db1, &v1);
|
||||
assert_non_null(v1);
|
||||
res = dns_db_findnode(db1, dns_rootname, true, &node);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
res = dns_db_findrdataset(db1, node, v1, dns_rdatatype_txt, 0, 0,
|
||||
&rdataset1, NULL);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
|
||||
/* db1: Convert result to text */
|
||||
res = dns_rdataset_first(&rdataset1);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
dns_rdataset_current(&rdataset1, &out1);
|
||||
|
||||
res = dns_rdata_totext(&out1, NULL, &b);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
isc_buffer_putuint8(&b, 0);
|
||||
|
||||
/* db1: We should have "text 1" */
|
||||
assert_string_equal(buf, "\"text 1\"");
|
||||
|
||||
dns_rdataset_disassociate(&rdataset1);
|
||||
|
||||
dns_db_closeversion(db1, &v1, true);
|
||||
assert_null(v1);
|
||||
dns_db_detachnode(db1, &node);
|
||||
assert_null(node);
|
||||
|
||||
/* db2: Look it up and check that the second version is found */
|
||||
dns_db_currentversion(db2, &v2);
|
||||
assert_non_null(v2);
|
||||
res = dns_db_findnode(db2, dns_rootname, true, &node);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
res = dns_db_findrdataset(db2, node, v2, dns_rdatatype_txt, 0, 0,
|
||||
&rdataset2, NULL);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
|
||||
/* db2: Convert result to text */
|
||||
res = dns_rdataset_first(&rdataset2);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
dns_rdataset_current(&rdataset2, &out2);
|
||||
isc_buffer_init(&b, buf, sizeof(buf));
|
||||
res = dns_rdata_totext(&out2, NULL, &b);
|
||||
assert_int_equal(res, ISC_R_SUCCESS);
|
||||
isc_buffer_putuint8(&b, 0);
|
||||
|
||||
/* db2: We should have "text 2" */
|
||||
assert_string_equal(buf, "\"text 2\"");
|
||||
|
||||
dns_rdataset_disassociate(&rdataset2);
|
||||
|
||||
dns_db_closeversion(db2, &v2, true);
|
||||
assert_null(v2);
|
||||
dns_db_detachnode(db2, &node);
|
||||
assert_null(node);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY_CUSTOM(find, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(allrdatasets, setup_test, teardown_test)
|
||||
@@ -373,6 +521,7 @@ ISC_TEST_ENTRY_CUSTOM(addrdataset, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(getnsec3parameters, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(attachversion, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(closeversion, setup_test, teardown_test)
|
||||
ISC_TEST_ENTRY_CUSTOM(rollback, setup_test, teardown_test)
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
ISC_TEST_MAIN
|
||||
|
||||
+19
-39
@@ -535,7 +535,6 @@ ISC_LOOP_TEST_IMPL(find) {
|
||||
|
||||
/* check issecuredomain() */
|
||||
ISC_LOOP_TEST_IMPL(issecuredomain) {
|
||||
bool issecure;
|
||||
const char **n;
|
||||
const char *names[] = { "example.com", "sub.example.com",
|
||||
"null.example", "sub.null.example", NULL };
|
||||
@@ -550,22 +549,16 @@ ISC_LOOP_TEST_IMPL(issecuredomain) {
|
||||
* of installing a null key).
|
||||
*/
|
||||
for (n = names; *n != NULL; n++) {
|
||||
assert_int_equal(dns_keytable_issecuredomain(keytable,
|
||||
str2name(*n), NULL,
|
||||
&issecure),
|
||||
ISC_R_SUCCESS);
|
||||
assert_true(issecure);
|
||||
assert_true(dns_keytable_issecuredomain(keytable, str2name(*n),
|
||||
NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* If the key table has no entry (not even a null one) for a domain or
|
||||
* any of its ancestors, that domain is considered insecure.
|
||||
*/
|
||||
assert_int_equal(dns_keytable_issecuredomain(keytable,
|
||||
str2name("example.org"),
|
||||
NULL, &issecure),
|
||||
ISC_R_SUCCESS);
|
||||
assert_false(issecure);
|
||||
assert_false(dns_keytable_issecuredomain(
|
||||
keytable, str2name("example.org"), NULL));
|
||||
|
||||
destroy_tables();
|
||||
|
||||
@@ -595,7 +588,7 @@ ISC_LOOP_TEST_IMPL(dump) {
|
||||
/* check negative trust anchors */
|
||||
ISC_LOOP_TEST_IMPL(nta) {
|
||||
isc_result_t result;
|
||||
bool issecure, covered;
|
||||
bool covered;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *keyname = dns_fixedname_name(&fn);
|
||||
unsigned char digest[ISC_MAX_MD_SIZE];
|
||||
@@ -626,20 +619,15 @@ ISC_LOOP_TEST_IMPL(nta) {
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
/* Should be secure */
|
||||
result = dns_view_issecuredomain(myview,
|
||||
str2name("test.secure.example"), now,
|
||||
true, &covered, &issecure);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_true(dns_view_issecuredomain(
|
||||
myview, str2name("test.secure.example"), now, true, &covered));
|
||||
assert_false(covered);
|
||||
assert_true(issecure);
|
||||
|
||||
/* Should not be secure */
|
||||
result = dns_view_issecuredomain(myview,
|
||||
str2name("test.insecure.example"), now,
|
||||
true, &covered, &issecure);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_false(dns_view_issecuredomain(myview,
|
||||
str2name("test.insecure.example"),
|
||||
now, true, &covered));
|
||||
assert_true(covered);
|
||||
assert_false(issecure);
|
||||
|
||||
/* NTA covered */
|
||||
covered = dns_view_ntacovers(myview, now, str2name("insecure.example"),
|
||||
@@ -652,38 +640,30 @@ ISC_LOOP_TEST_IMPL(nta) {
|
||||
assert_false(covered);
|
||||
|
||||
/* As of now + 2, the NTA should be clear */
|
||||
result = dns_view_issecuredomain(myview,
|
||||
str2name("test.insecure.example"),
|
||||
now + 2, true, &covered, &issecure);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_true(dns_view_issecuredomain(myview,
|
||||
str2name("test.insecure.example"),
|
||||
now + 2, true, &covered));
|
||||
assert_false(covered);
|
||||
assert_true(issecure);
|
||||
|
||||
/* Now check deletion */
|
||||
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
|
||||
now, true, &covered, &issecure);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_true(dns_view_issecuredomain(
|
||||
myview, str2name("test.new.example"), now, true, &covered));
|
||||
assert_false(covered);
|
||||
assert_true(issecure);
|
||||
|
||||
result = dns_ntatable_add(ntatable, str2name("new.example"), false, now,
|
||||
3600);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
|
||||
now, true, &covered, &issecure);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_false(dns_view_issecuredomain(
|
||||
myview, str2name("test.new.example"), now, true, &covered));
|
||||
assert_true(covered);
|
||||
assert_false(issecure);
|
||||
|
||||
result = dns_ntatable_delete(ntatable, str2name("new.example"));
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
|
||||
now, true, &covered, &issecure);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_true(dns_view_issecuredomain(
|
||||
myview, str2name("test.new.example"), now, true, &covered));
|
||||
assert_false(covered);
|
||||
assert_true(issecure);
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user