Compare commits

..
Author SHA1 Message Date
Evan Hunt 14271bf4e2 fixup! fixup! refactor validated() 2025-03-14 18:29:48 -07:00
Evan Hunt db6e91497c fixup! split out some functionality in cache_name() 2025-03-14 18:29:48 -07:00
Evan Hunt b735f2e821 fixup! refactor validated() 2025-03-14 18:29:48 -07:00
Evan Hunt e39d265a99 refactor validated()
- there was special-case code in validated() to handle the results
  of a validator started by a CD=1 query. since that never happens,
  the code has been removed.
- the section of code that handles opportunistic caching of
  validated SOA, NS and NSEC data has been split out to a separate
  function.
- the number of goto statements has been reduced considerably.
2025-03-14 18:29:48 -07:00
Evan Hunt 8f03f31106 split out helper functions
- fctx_setresult() sets the event result in a fetch response
  according to the rdataset being returned - DNS_R_NCACHENXDOMAIN or
  DNS_R_NXRRSET for negative responses, ISC_R_SUCCESS, DNS_R_CNAME,
  or DNS_R_DNAME for positive ones.
- cache_rrset() looks up a node and adds an rdataset.
- delete_rrset() looks up a node and removes rdatasets of a specified
  type and, optionally, the associated signatures.
- gettrust() returns the trust level of an rdataset, or dns_trust_none
  if the rdataset is NULL or not associated.
- getrrsig() scans the rdatasets associated with a name for the
  RRSIG covering a given type.
2025-03-14 18:29:48 -07:00
Evan Hunt d3d981f38e further subdivide caching functions
rctx_cacherdataset() has been split into two functions:
- rctx_cache_secure() starts validation for rdatasets
  that need it; they are then cached by the validator
  completion callback validated()
- rctx_cache_insecure() caches rdatasets immediately; it
  is called when validation is disabled or the data
  to be cached is glue.
2025-03-14 18:29:48 -07:00
Evan Hunt 6c291971db rename and refactor cache_name() and related functions
- renamed cache_message() to rctx_cachemessage()
- renamed cache_name() to rctx_cachename()
- merged ncache_message() into rctx_ncache()
- split out a new function, rctx_cacherdataset(), which is
  called by rctx_cachename() in a loop to process each of
  the rdatasets associated with the name.
2025-03-14 18:29:48 -07:00
Evan Hunt d61dc02a7c reduce code duplication around findnoqname()
every call to findnoqname() was followed by a call to
dns_rdataset_addnoqname(). we can move that call into
findnoqname() itself, and simplify the calling functions
a bit.
2025-03-14 18:29:48 -07:00
Evan Hunt 503c7a86fe set ANSWERSIG flag when processing ANY responses
previously, rctx_answer_any() set the ANSWER flag for all
rdatasets in the answer section; it now sets ANSWERSIG for
RRSIG/SIG rdatasets and ANSWER for everything else.  this
error didn't cause any harm in the current code, but it
could have led to unexpected behavior in the future.
2025-03-14 18:29:48 -07:00
Evan Hunt 6876c06918 split out some functionality in cache_name()
there are now separate functions to check the cacheability of
an rdataset or to normalize TTLs, and the code to determine
whether validation is necessary has been simplified.
2025-03-14 18:29:48 -07:00
Evan Hunt fdb9a24d18 add functions to match rdataset types
- dns_rdataset_issigtype() returns true if the rdataset is
  of type RRSIG and covers a specified type
- dns_rdataset_matchestype() returns true if the rdataset
  is of the specified type *or* the RRSIG covering it.
2025-03-14 18:29:48 -07:00
Evan Hunt ea33257ad0 reduce steps for negative caching
whenever ncache_adderesult() was called, some preparatory code
was run first; this has now been moved into a single function
negcache() to reduce code duplication.
2025-03-14 18:29:48 -07:00
Evan Hunt dd971ad4e4 change issecuredomain() functions to bool
dns_keytable_issecuredomain() and dns_view_issecuredomain()
previously returned a result code to inform the caller of
unexpected database failures when looking up names in the
keytable and/or NTA table. such failures are not actually
possible. both functions now return a simple bool.

also, dns_view_issecuredomain() now returns false if
view->enablevalidation is false, so the caller no longer
has to check for that.
2025-03-14 18:29:48 -07:00
Evan Hunt 8368ef5ae7 split out cookie checks from resquery_response_continue()
split the code section that handles cookie issues into a
separate function for better readablity.
2025-03-14 18:29:48 -07:00
Evan Hunt d8778caec7 simplify dns_ncache_add()
there's no longer any reason to have both dns_ncache_add() and
dns_ncache_addoptout().
2025-03-14 18:29:48 -07:00
Evan Hunt a8dd267bd0 fix: nil: Add new convenience functions to classify rdata types
- `dns_rdatatype_ismulti()` returns true if a given type can have
  multiple answers: ANY, RRSIG, or SIG.
- `dns_rdatatype_issig()` returns true for a signature: RRSIG or SIG.
- `dns_rdatatype_isaddr()` returns true for an address: A or AAAA.
- `dns_rdatatype_isalias()` returns true for an alias: CNAME or DNAME.

Code has been modified to use these functions where applicable.

These and all similar functions (e.g., `dns_rdatatype_ismeta()`, `dns_rdatatype_issingleton()`, etc) are now `static inline` functions defined in `rdata.h`.

Merge branch 'each-rdatatype-functions' into 'main'

See merge request isc-projects/bind9!10216
2025-03-15 01:26:35 +00:00
Evan Hunt 606d30796e use new dns_rdatatype classification functions
modify code to use dns_rdatatype_ismulti(), dns_rdatatype_issig(),
dns_rdatatype_isaddr(), and dns_rdatatype_isalias() where applicable.
2025-03-15 00:27:54 +00:00
Evan Hunt 37ff0aa9c0 convert rdatatype classification routines to inline
turn the dns_rdatatype_is*() functions into static inline
functions in rdata.h.
2025-03-15 00:27:54 +00:00
Evan Hunt 1c51d44d82 add new functions to classify rdata types
- dns_rdatatype_ismulti() returns true if a given type can have
  multiple answers: ANY, RRSIG, or SIG.
- dns_rdatatype_issig() returns true for a signature: RRSIG or SIG.
- dns_rdatatype_isaddr() returns true for an address: A or AAAA.
- dns_rdatatype_isalias() returns true for an alias: CNAME or DNAME.
2025-03-15 00:27:54 +00:00
Evan Hunt 3b0b658a52 fix: dev: step() could ignore rollbacks
The `step()` function (used for stepping to the prececessor or successor of a database node) could overlook a node if there was an rdataset that was marked IGNORE because it had been rolled back, covering an active rdataset under it.

Closes #5170

Merge branch '5170-step-ignores-rollback' into 'main'

See merge request isc-projects/bind9!10103
2025-03-14 23:19:36 +00:00
Evan Hunt ecde0ea2d7 add a unit test with an empty node
the db_test unit test now looks up an empty nonterminal node
to exercise the behavior of the step() function in qpzone.
2025-03-14 23:19:17 +00:00
Evan Hunt 7d98aba3ac add a unit test to check database rollback
check that a database rollback works and the correct
(original) data is found on lookup.
2025-03-14 23:19:17 +00:00
Evan Hunt 24eaff7adc qpzone.c:step() could ignore rollbacks
the step() function (used for stepping to the prececessor or
successor of a database node) could overlook a node because
there was an rdataset marked IGNORE because it had been rolled
back, covering an active rdataset under it.
2025-03-14 23:19:17 +00:00
Evan Hunt 025ef4d7b8 fix: dev: Fix handling of revoked keys
When a key is revoked, its key ID changes due to the inclusion of the "revoked" flag. A collision between this changed key ID
and an unrelated public-only key could cause a crash in `dnssec-signzone`.

Closes #5231

Merge branch '5231-fix-keyid-collision' into 'main'

See merge request isc-projects/bind9!10233
2025-03-14 22:26:36 +00:00
Evan Hunt 9cfe9f5eb7 fix handling of revoked keys
when a key is revoked its key ID changes, due to the inclusion
of the "revoke" flag. a collision between this changed key ID and
that of an unrelated public-only key could cause a crash in
dnssec-signzone.
2025-03-14 22:25:44 +00:00
Mark Andrews e6c07b3386 fix: test: Tune many types tests in reclimit test
The `I:checking that lifting the limit will allow everything to get
cached (20)` test was failing due to the TTL of the records being
too short for the elapsed time of the test.  Raise the TTL to fix
this and adjust other tests as needed.

Closes #5206

Merge branch '5206-tune-last-sub-test-of-reclimit' into 'main'

See merge request isc-projects/bind9!10177
2025-03-14 05:28:01 +00:00
Mark Andrews 1a58bd2113 Tune many types tests in reclimit test
The 'I:checking that lifting the limit will allow everything to get
cached (20)' test was failing due to the TTL of the records being
too short for the elapsed time of the test.  Raise the TTL to fix
this and adjust other tests as needed.
2025-03-14 02:03:50 +00:00
Mark Andrews 42799ae81f fix: usr: QNAME minimization could leak the query type
When performing QNAME minimization, `named` now sends an NS query for the original query name, before sending the final query. This prevents the parent zone from learning the original query type, in the event that the query name is a delegation point.

For example, when looking up an address record for `example.com`, NS queries are now sent to the servers for both `com` and `example.com`, before the address query is sent to the servers for `example.com`.  Previously, an address query would have been sent to the servers for `com`.

Closes #4805

Merge branch '4805-missing-qname-ns-query-when-using-qname-minimisation' into 'main'

See merge request isc-projects/bind9!9155
2025-03-14 02:02:52 +00:00
Mark Andrews de519cd1c9 Don't leak the original QTYPE to parent zone
When performing QNAME minimization, named now sends an NS
query for the original QNAME, to prevent the parent zone from
receiving the QTYPE.

For example, when looking up example.com/A, we now send NS queries
for both com and example.com before sending the A query to the
servers for example.com.  Previously, an A query for example.com
would have been sent to the servers for com.

Several system tests needed to be adjusted for the new query pattern:

- Some queries in the serve-stale test were sent to the wrong server.
- The synthfromdnssec test could fail due to timing issues; this
  has been addressed by adding a 1-second delay.
- The cookie test could fail due to the a change in the count of
  TSIG records received in the "check that missing COOKIE with a
  valid TSIG signed response does not trigger TCP fallback" test case.
- The GL #4652 regression test case in the chain system test depends
  on a particular query order, which no longer occurs when QNAME
  minimization is active. We now disable qname-minimization
  for that test.
2025-03-14 01:01:26 +00:00
Mark Andrews 496f7963cd Fix handling of ISC_R_TIMEOUT in resume_qmin()
If a timeout occurs when sending a QMIN query, QNAME
minimization should be disabled. This now causes a hard
failure in strict mode, or a fallback to non-minimized queries
in relaxed mode.
2025-03-14 01:01:26 +00:00
Mark Andrews 98fc14dc75 Exempt QNAME minimization queries from fetches-per-zone
The calling fetch has already called fcount_incr() for this zone;
calling it again for a QMIN query results in double counting.

When resuming after a QMIN query is answered, however, we do now
ensure before continuing that the fetches-per-zone limit has not
been exceeded.
2025-03-14 01:01:26 +00:00
Mark Andrews 3397212df3 new: usr: dig can now display the received BADVERS message during negotiation
Dig +showbadvers now displays the received BADVERS message and 
continues the EDNS version negotiation.  Previously to see the
BADVERS message +noednsneg had to be specified which terminated the
EDNS negotiation.  Additionally the specified EDNS value (+edns=value)
is now used when making all the initial queries with +trace. i.e EDNS
version negotiation will be performed with each server when performing
the trace.

Closes #5234

Merge branch '5234-have-dig-display-the-badvers-message' into 'main'

See merge request isc-projects/bind9!10234
2025-03-14 00:45:20 +00:00
Mark Andrews 947ca25663 check that dig +showbadvers works 2025-03-13 21:36:14 +00:00
Mark Andrews 6c271f6328 Add "+showbadvers" to dig and reset EDNS version
Add "+showbadvers" to display the BADVERS response similarly
to "+showbadcookie".  Additionally reset the EDNS version to
the requested version in "dig +trace" so that EDNS version
negotiation can be tested at all levels of the trace rather
that just when requesting the root nameservers.
2025-03-13 21:36:14 +00:00
Matthijs Mekking 6ac4cfb948 fix: usr: Ensure max-clients-per-query is at least clients-per-query
If the `max-clients-per-query` option is set to a lower value than `clients-per-query`, the value is adjusted to match `clients-per-query`.

Closes #5224

Merge branch '5224-raise-max-clients-per-query-to-be-at-least' into 'main'

See merge request isc-projects/bind9!10241
2025-03-13 13:02:48 +00:00
Matthijs Mekking f6f9645ed1 Raise max-clients-per-query to be at least
In the case where 'clients-per-query' is larger than
'max-clients-per-query', raise 'max-clients-per-query' so that
'clients-per-query' equals 'max-clients-per-query' and log a warning
that this is what happened.
2025-03-13 13:02:28 +00:00
Matthijs Mekking 1f674ef42e Test new max-clients-per-query log warning
Make sure the new warning is logged.
2025-03-13 13:02:28 +00:00
Matthijs Mekking f50753f303 Update max-clients-per-query documentation
The new intended behavior is that 'max-clients-per-query' value is
raised to equal 'clients-per-query' if it is lower.
2025-03-13 13:02:28 +00:00
Colin Vidal 45ee3715e1 new: usr: Add support for EDE 20 (Not Authoritative)
Support was added for EDE codes 20 (Not Authoritative) when client requests recursion (RD) but the server has recursion disabled.

RFC 8914 mention EDE 20 should also be returned if the client doesn't have the RD bit set (and recursion is needed) but it doesn't apply for
BIND as BIND would try to resolve from the "deepest" referral in AUTHORITY section. For example, if the client asks for "www.isc.org/A" but the server only knows the root domain, it will return NOERROR but no answer for "www.isc.og/A", just the list of other servers to ask.

See #1836

Merge branch '1836-not-authoritative' into 'main'

See merge request isc-projects/bind9!10228
2025-03-13 11:56:37 +00:00
Colin Vidal 7f613c207f add system test covering EDE 20
Add system test to cover extended DNS error 20 (Not authoritative).
2025-03-13 11:16:01 +01:00
Colin Vidal 24ffbdcfea add support for EDE 20 (Not Authoritative)
Extended DNS Error message EDE 20 (Not Authoritative) is now sent when
client request recursion (RD) but the server has recursion disabled.

RFC 8914 mention EDE 20 should also be returned if the client doesn't
have the RD bit set (and recursion is needed) but it doesn't apply for
BIND as BIND would try to resolve from the "deepest" referral in
AUTHORITY section. For example, if the client asks for "www.isc.org/A"
but the server only knows the root domain, it will returns NOERROR but
no answer for "www.isc.og/A", just the list of other servers to ask.
2025-03-13 11:16:01 +01:00
Colin Vidal e66dc07c68 new: usr: Add support for EDE 7 and EDE 8
Support was added for EDE codes 7 (Signature Expired) and 8 (Signature Not Yet Valid) which might occur during DNSSEC validation.

See #2715

Merge branch '2715-expired-future-keys' into 'main'

See merge request isc-projects/bind9!10225
2025-03-13 10:13:36 +00:00
Colin Vidal e763d6637f add system tests covering EDE 7 and 8
Add DNSSEC system tests to cover extended DNS error 7 (Signature
Expired) and 8 (Signature Not Yet Valid).
2025-03-13 09:57:09 +01:00
Colin Vidal 334ea1269f add support for EDE 7 and 8
Extended DNS Error messages EDE 7 (expired key) and EDE 8 (validity
period of the key not yet started) are now sent in case of such DNSSEC
validation failures.

Refactor the existing validator extended error APIs in order to make it
easy to have a consisdent extra info (with domain/type) in the various
use case (i.e. when the EDE depends on validator state,
validate_extendederror or when the EDE doesn't depend of any state but
can be called directly in a specific flow).
2025-03-13 09:57:09 +01:00
Matthijs Mekking 3309863c97 fix: test: Take into account key collisions in ksr system test
Closes #5229

Merge branch '5229-ksr-system-test-can-fail-on-key-collision' into 'main'

See merge request isc-projects/bind9!10238
2025-03-13 08:19:05 +00:00
Matthijs Mekking 8b3d2e5633 ksr: Take into account key collisions
When generating new key pairs, one test checks if existing keys that
match the time bundle are selected, rather than extra keys being
generated. Part of the test is to check the verbose output, counting
the number of "Selecting" and "Generating" occurences. But if there
is a key collision, the ksr tool will output that the key already
exists and includes the substring "already exists, or might collide
with another key upon revokation.  Generating a new key".

So substract by one the generated counter if there is a "collide"
occurrence.
2025-03-13 08:18:50 +00:00
Matthijs Mekking 3973c2e8c3 fix: dev: Fix CID 544147: Code maintainability issues (UNUSED_VALUE)
Assigning value "NULL" to "newstr", but that stored value is overwritten
before it can be used.

Setting "newstr" to NULL does not have any effect, so the line can
safely be removed.

Closes #5227

Merge branch '5227-cid-544147' into 'main'

See merge request isc-projects/bind9!10239
2025-03-13 08:18:35 +00:00
Matthijs Mekking ecef45bf18 Fix CID 544147
Assigning value "NULL" to "newstr", but that stored value is overwritten
before it can be used.

Setting "newstr" to NULL does not have any effect, so the line can
safely be removed.
2025-03-12 16:39:36 +01:00
Andoni Duarte 33a0cc9823 chg: doc: Set up version for BIND 9.21.7
Merge branch 'andoni/set-up-version-for-bind-9.21.7' into 'main'

See merge request isc-projects/bind9!10237
2025-03-12 13:07:00 +00:00
Andoni Duarte Pintado bd711bb839 Update BIND version to 9.21.7-dev 2025-03-12 12:09:35 +01:00
67 changed files with 2699 additions and 3334 deletions
+16 -2
View File
@@ -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");
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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))))
{
-1
View File
@@ -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
View File
@@ -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);
/*
+1
View File
@@ -28,6 +28,7 @@ options {
} except-from {
"example";
};
qname-minimization disabled; // Regression test for GL #4652
};
trust-anchors { };
+9 -4
View File
@@ -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
+10
View File
@@ -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
+1 -1
View File
@@ -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
+27 -2
View File
@@ -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"
+2 -6
View File
@@ -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";
};
+9
View File
@@ -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
-52
View File
@@ -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'
+27 -628
View File
@@ -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
+7 -6
View File
@@ -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}"
+41 -41
View File
@@ -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}"
-28
View File
@@ -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
View File
@@ -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}
-569
View File
@@ -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)
+59 -33
View File
@@ -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)
+3 -3
View File
@@ -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))
+3 -2
View File
@@ -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.
+23
View File
@@ -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
+2 -2
View File
@@ -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
+25 -25
View File
@@ -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;
};
+1
View File
@@ -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)
+13 -4
View File
@@ -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
+1 -1
View File
@@ -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.
+12 -11
View File
@@ -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*",
+4 -3
View File
@@ -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
View File
@@ -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
+7 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+5 -14
View File
@@ -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
+9 -11
View File
@@ -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
View File
@@ -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);
/*%<
+27
View File
@@ -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;
}
+1
View File
@@ -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,
+3 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+149
View File
@@ -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
View File
@@ -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);