Compare commits

..
Author SHA1 Message Date
Colin Vidal 19ace9e681 fixup! add system tests covering EDE 9 2025-03-20 10:57:28 +01:00
Colin Vidal e2b027001b add system tests covering EDE 9
Add DNSSEC system tests covering extended DNS error 9. Because BIND9 won't
returned signed records (RRSIG) when provided a signed zone without DNSKEY
records, this test involves a new mock DNS server which loads a
fully signed zone and return associated RRSIG to its RR, but also return NODATA
when the query type is DNSKEY. This enable to run a resolver trying to validate
a domain, but failing because it can't get the DNSKEY, thus expecting the EDE 9
message.
2025-03-19 17:47:48 +01:00
Colin Vidal c9b7857387 add support for EDE 9
Extended DNS Error 9 (Missing DNSKEY) is now sent when a validating resolver
attempts to validate a response but can't get the DNSKEY from the authoritative
server.

The EDE 9 is sent only in the proveunsecure flow because we want to
send it only in the case there has to be a validation, so we need to
make sure the parent domain has a DS record to the children.
2025-03-19 17:47:48 +01:00
Andoni Duarte Pintado 8dba96d71e Merge tag 'v9.21.6' 2025-03-19 17:36:14 +01:00
Michal Nowak 1d688e89b8 fix: test: Fix the log-report-channel zones check
The check looks for logs that are not present, fails to make the
possible failure visible, and fails to bump the check enumerator:

    I:checking that log-report-channel zones fail if '*._er/TXT' is missing (129)
    grep: test.out4.129: No such file or directory
    grep: test.out4.129: No such file or directory
    I:checking that raw zone with bad class is handled (129)

The issue appeared in #3659.

Merge branch 'mnowak/checkzone-test-fix' into 'main'

See merge request isc-projects/bind9!10286
2025-03-19 08:00:42 +00:00
Michal Nowak c2e60f9a5a Fix the log-report-channel zones check
The check looks for logs that are not present, fails to make the
possible failure visible, and fails to bump the check enumerator:

    I:checking that log-report-channel zones fail if '*._er/TXT' is missing (129)
    grep: test.out4.129: No such file or directory
    grep: test.out4.129: No such file or directory
    I:checking that raw zone with bad class is handled (129)
2025-03-19 08:00:19 +00:00
Mark Andrews ed727ee924 fix: test: Fix failing grep invocation on OpenBSD
Lines starting with A or NSEC are expected but not matched with the
OpenBSD grep. Extended regular expressions with direct use of
parentheses and the pipe symbol is more appropriate.

    I:checking RRSIG query from cache (154)
    I:failed

The issue appeared in #4805.

Merge branch 'mnowak/openbsd-grep-fix' into 'main'

See merge request isc-projects/bind9!10285
2025-03-19 00:04:39 +00:00
Michal NowakandMark Andrews 00584d6f29 Fix failing grep invocation on OpenBSD
Lines starting with A or NSEC are expected but not matched with the
OpenBSD grep. Extended regular expressions with direct use of
parentheses and the pipe symbol is more appropriate.

    I:checking RRSIG query from cache (154)
    I:failed
2025-03-18 23:29:22 +00:00
Arаm Sаrgsyаn d30b9eb46e fix: usr: Fix resolver statistics counters for timed out responses
When query responses timed out, the resolver could incorrectly increase the regular responses counters, even if no response was received. This has been fixed.

Closes #5193

Merge branch '5193-resolver-statistics-counters-fix' into 'main'

See merge request isc-projects/bind9!10227
2025-03-18 17:05:23 +00:00
Aram Sargsyan 0c7fa8d572 Test resolver statistics when responses time out
Add a test to check that the timed out responses do not skew the
normal responses statistics counters, and that they do update the
timeouts counter.
2025-03-18 16:20:59 +00:00
Aram Sargsyan 830e548111 Fix the resolvers RTT-ranged responses statistics counters
When a response times out the fctx_cancelquery() function
incorrectly calculates it in the 'dns_resstatscounter_queryrtt5'
counter (i.e. >=1600 ms). To avoid this, the rctx_timedout()
function should make sure that 'rctx->finish' is NULL. And in order
to adjust the RTT values for the timed out server, 'rctx->no_response'
should be true. Update the rctx_timedout() function to make those
changes.
2025-03-18 16:20:59 +00:00
Aram Sargsyan 12e7dfa397 Fix resolver responses statistics counter
The resquery_response() function increases the response counter without
checking if the response was successful. Increase the counter only when
the result indicates success.
2025-03-18 16:20:59 +00:00
Michał Kępień c6e5710846 chg: test: asyncserver.py: TCP improvements
This branch started off as `michal/upforwd-asyncserver`.  It quickly
turned out that the critical `asyncserver.py` change that was needed for
the `upforwd` system test was for the server to be able to read multiple
TCP queries on a single connection.  As currently present in `main`,
`asyncserver.py` closes every client connection after servicing a single
query.  Retaining that behavior would cause the `upforwd` system test to
fail and, in general, capturing all data sent by a client seems more
useful in tests than just closing connections quickly.  `asyncserver.py`
can always be extended in the future (e.g. by adding a new
`ResponseAction` that the networking code would react to) to reinstate
the original behavior, if it turns out to be necessary.

While working on changing that particular `asyncserver.py` behavior, I
noticed a couple of other deficiencies in the TCP connection handling
code, so I started addressing them.  One thing led to another and before
I noticed, enough changes were applied to be worth doing a separate
merge request, particularly given that the actual rewrite of
`upforwd/ans4/ans.pl` using `asyncserver.py` is trivial once the
required changes to `asyncserver.py` itself are applied.

Merge branch 'michal/asyncserver-tcp-improvements' into 'main'

See merge request isc-projects/bind9!10276
2025-03-18 15:30:35 +00:00
Michał Kępień 575a874582 Handle queries indefinitely on each TCP connection
Instead of closing every incoming TCP connection after handling a single
query, continue receiving queries on each TCP connection until the
client disconnects itself.  When coupled with response dropping, this
enables silently receiving all incoming data, simulating an unresponsive
server.
2025-03-18 16:28:18 +01:00
Michał Kępień 68fe9a5df5 Enable receiving chunked TCP DNS messages
A TCP DNS client may send its queries in chunks, causing
StreamReader.read() to return less data than previously declared by the
client as the DNS message length; even the two-octet DNS message length
itself may be split up into two single-octet transmissions.  Sending
data in chunks is valid client behavior that should not be treated as an
error.  Add a new helper method for reading TCP data in a loop, properly
distinguishing between chunked queries and client disconnections.  Use
the new method for reading all TCP data from clients.
2025-03-18 16:28:18 +01:00
Michał Kępień 8c3f673f37 Extend TCP logging
Emit more log messages from TCP connection handling code and extend
existing ones to improve debuggability of servers using asyncserver.py.
2025-03-18 16:28:18 +01:00
Michał Kępień 748ed4259b Handle connection resets during reading
A TCP peer may reset the connection at any point, but asyncserver.py
currently only handles connection resets when it is sending data to the
client.  Handle connection resets during reading in the same way.
2025-03-18 16:28:18 +01:00
Michał Kępień a956947fba Refactor AsyncDnsServer._handle_tcp()
Split up AsyncDnsServer._handle_tcp() into a set of smaller methods to
improve code readability.
2025-03-18 16:28:18 +01:00
Michał Kępień e4c3186a7c Gracefully handle TCP client disconnections
Prevent premature client disconnections during reading from triggering
unhandled exceptions in TCP connection handling code.
2025-03-18 16:28:18 +01:00
Michał Kępień 5764a9d660 Simplify peer address formatting
Add a helper class, Peer, which holds the <host, port> tuple of a
connection endpoint and gets pretty-printed when formatted as a string.
This enables passing instances of this new class directly to logging
functions, eliminating the need for the AsyncDnsServer._format_peer()
helper method.
2025-03-18 16:28:18 +01:00
Nicki Křížek a2042e603e chg: ci: Allow re-run of the shotgun jobs to reduce false positives
The false positive rate is about 10-20 % when evaluating shotgun results
from a single run. Attempt to reduce the false positive rate by allowing
a re-run of failed jobs.

Merge branch 'nicki/ci-shotgun-reduce-false-positives' into 'main'

See merge request isc-projects/bind9!10271
2025-03-18 09:29:10 +00:00
Nicki Křížek 5eab352478 Allow re-run of the shotgun jobs to reduce false positive
The false positive rate is about 10-20 % when evaluating shotgun results
from a single run. Attempt to reduce the false positive rate by allowing
a re-run of failed jobs.

While there is a slight risk that barely noticable decreases in
performance might slip by more easily in MRs, they'd still likely pop up
during nightly or pre-release testing.

Also increase the tolerance threshold for DoH latency comparisons, as
those tests often experience increased jitter in the tail end latencies.
2025-03-18 10:19:32 +01:00
Nicki Křížek 7f8226a039 Adjust the load factor for shotgun:tcp test
With the slightly decreased load for the TCP test, the results appear to
be a little bit more stable.
2025-03-18 10:19:32 +01:00
Michał Kępień 192627db10 chg: test: Use isctest.asyncserver in the "qmin" test
Replace custom DNS servers used in the "qmin" system test with new code
based on the isctest.asyncserver module.  The revised code employs zone
files and a limited amount of custom logic, which massively improves
test readability and maintainability, extends logging, and fixes
non-compliant replies sent by some of the custom servers in response to
certain queries (e.g. AA=0 in authoritative empty non-terminal
responses, non-glue address records in ADDITIONAL section).

Merge branch 'michal/qmin-asyncserver' into 'main'

See merge request isc-projects/bind9!10195
2025-03-18 05:55:17 +00:00
Michał Kępień dfd37918d6 Broaden vulture exclude glob for ans.py servers
The vulture tool seems to be unable to follow how the parent classes
defined in bin/tests/system/qmin/qmin_ans.py use mandatory properties
specified by child classes in bin/tests/system/qmin/ans*/ans.py.  Make
the tool ignore not just ans.py servers, but also *_ans.py utility
modules above the ansX/ subdirectories to prevent false positives about
unused code from causing CI pipeline failures.
2025-03-18 06:19:01 +01:00
Michał Kępień f413ddbe5f Ignore .hypothesis files created by system tests
Some versions of the Hypothesis Python library - notably the one
included in stock OS repositories for Ubuntu 20.04 Focal Fossa - cause a
.hypothesis file to be created in a Python script's working directory
when the hypothesis module is present in its import chain.  Ignore such
files by adding them to the list of expected test artifacts to prevent
pytest teardown checks from failing due to these files appearing in the
file system after running system tests.
2025-03-18 06:19:01 +01:00
Michał Kępień a799dd04ad Fix PYTHONPATH set for ans.py servers by start.pl
Commit 6c010a5644 caused the PYTHONPATH
environment variable to be set for ans.py servers started using
start.pl.  However, no system test has actually used the new
isctest.asyncserver module since that change was applied, so it has not
been noticed until now that including the source directory in PYTHONPATH
is only sufficient for in-tree builds.  Include the build directory
instead of the source directory in the PYTHONPATH environment variable
set for ans.py servers started by start.pl so that they work correctly
for both in-tree and out-of-tree builds.
2025-03-18 06:19:01 +01:00
Michał Kępień 7faa34c6ee Use isctest.asyncserver in the "qmin" test
Replace custom DNS servers used in the "qmin" system test with new code
based on the isctest.asyncserver module.  The revised code employs zone
files and a limited amount of custom logic, which massively improves
test readability and maintainability, extends logging, and fixes
non-compliant replies sent by some of the custom servers in response to
certain queries (e.g. AA=0 in authoritative empty non-terminal
responses, non-glue address records in ADDITIONAL section).
2025-03-18 06:19:01 +01:00
Ondřej Surý 575a2e5f11 rem: dev: Cleanup BIND 8 compatibility code
There was some code in dns_resolver unit meant to keep compatibility with BIND 8 breaking the DNS protocol.  These should not be needed anymore.

Merge branch 'ondrej/resolver-bind-8-cleanup' into 'main'

See merge request isc-projects/bind9!10270
2025-03-18 00:12:31 +00:00
Ondřej SurýandEvan Hunt 0d9f58b745 Remove a kludge to process non-authoritative CNAME response
A BIND 8 server could return a non-authoritative answer when a CNAME is
followed.  This is no longer handled as a valid answer.
2025-03-17 23:23:24 +00:00
Ondřej SurýandEvan Hunt 05d6542e6d Remove the kludges for records in the bad sections
There were kludges to help process responses from authoritative servers
giving RRs in wrong sections (mentioning BIND 8).  These should just go
away and such responses should not be processed.
2025-03-17 23:23:24 +00:00
Ondřej SurýandEvan Hunt ff73d37f69 Small cleanup in dns_adb unit 2025-03-17 23:23:24 +00:00
Michal Nowak 9d9e9d9cb1 chg: ci: Disable linkcheck on dl.acm.org
The check fails with the following error for some time:

    403 Client Error: Forbidden for url: https://dl.acm.org/doi/10.1145/1315245.1315298

Merge branch 'mnowak/linkcheck-disable-dl-acm-org' into 'main'

See merge request isc-projects/bind9!10272
2025-03-17 17:07:40 +00:00
Michal Nowak 1ab889ee21 Disable linkcheck on dl.acm.org
The check fails with the following error for some time:

    403 Client Error: Forbidden for url: https://dl.acm.org/doi/10.1145/1315245.1315298
2025-03-17 17:39:36 +01:00
Arаm Sаrgsyаn ae2fd7ef15 new: dev: Implement -T cookiealwaysvalid
When `-T cookiealwaysvalid` is passed to `named`, DNS cookie checks for
the incoming queries always pass, given they are structurally correct.

Merge branch 'aram/new-named-minus-T-option-of-cookiealwaysvalid' into 'main'

See merge request isc-projects/bind9!10232
2025-03-17 11:36:57 +00:00
Aram Sargsyan 4e75a20b6a Test -T cookiealwaysvalid
Add a check in the "cookie" system test to make sure that the new
'-T cookiealwaysvalid' option works.
2025-03-17 10:42:47 +00:00
Aram Sargsyan 807ef8545d Implement -T cookiealwaysvalid
When -T cookiealwaysvalid is passed to named, DNS cookie checks for
the incoming queries always pass, given they are structurally correct.
2025-03-17 10:42:47 +00:00
Mark Andrews 06427720f7 fix: dev: Add missing locks when returning addresses
Add missing locks in dns_zone_getxfrsource4 et al.  Addresses CID 468706, 468708, 468741, 468742, 468785, and 468778.

Cleanup dns_zone_setxfrsource4 et al to now return void.

Remove double copies with dns_zone_getprimaryaddr and dns_zone_getsourceaddr.

Closes #4933

Merge branch '4933-add-missing-locks-when-returning-addresses' into 'main'

See merge request isc-projects/bind9!9485
2025-03-15 06:04:34 +00:00
Mark Andrews d0a59277fb Add missing locks when returning addresses
Add missing locks in dns_zone_getxfrsource4 et al. Addresses CID
468706, 468708, 468741, 468742, 468785 and 468778.

Cleanup dns_zone_setxfrsource4 et al to now return void.

Remove double copies with dns_zone_getprimaryaddr and dns_zone_getsourceaddr.
2025-03-15 04:51:59 +00: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
Andoni Duarte Pintado 21ca763bca Update BIND version for release 2025-03-11 11:37:59 +01:00
Andoni Duarte 474b7a04f1 new: doc: Prepare documentation for BIND 9.21.6
Merge branch 'andoni/prepare-documentation-for-bind-9.21.6' into 'v9.21.6-release'

See merge request isc-private/bind9!784
2025-03-11 10:10:19 +00:00
Andoni Duarte Pintado 5dfcedd52d Tweak and reword relase notes 2025-03-11 10:46:21 +01:00
Andoni Duarte Pintado 7c308c2298 Prepare release notes for BIND 9.21.6 2025-03-11 10:46:21 +01:00
Andoni Duarte Pintado f0b5f0cbce Generate changelog for BIND 9.21.6 2025-03-11 10:46:21 +01:00
136 changed files with 10502 additions and 9002 deletions
+6 -6
View File
@@ -383,6 +383,9 @@ stages:
SHOTGUN_ROUNDS: 3
- &shotgun_rule_other
if: '$CI_PIPELINE_SOURCE =~ /^(api|pipeline|schedule|trigger|web)$/'
# when using data from a single run, the overall instability of the results
# causes quite high false positive rate, rerun the test to attemp to reduce those
retry: 1
script:
- if [ -z "$BASELINE" ]; then export BASELINE=$BIND_BASELINE_VERSION; fi # this dotenv variable can't be set in the rules section, because rules are evaluated before any jobs run
- PIPELINE_ID=$(curl -s -X POST --fail
@@ -584,7 +587,7 @@ vulture:
<<: *precheck_job
needs: []
script:
- vulture --exclude "*/ans*/ans.py,conftest.py,isctest" --ignore-names "pytestmark" bin/tests/system/
- vulture --exclude "*ans.py,conftest.py,isctest" --ignore-names "pytestmark" bin/tests/system/
ci-variables:
stage: precheck
@@ -1688,9 +1691,6 @@ respdiff-third-party:
# Performance tests
# Run shotgun:udp right away, but delay other shotgun jobs sligthly in order to
# allow re-use of the built container image. Otherwise, the jobs would do the
# same builds in parallel rather than re-use the already built image.
shotgun:udp:
<<: *shotgun_job
variables:
@@ -1701,7 +1701,7 @@ shotgun:tcp:
<<: *shotgun_job
variables:
SHOTGUN_SCENARIO: tcp
SHOTGUN_TRAFFIC_MULTIPLIER: 13
SHOTGUN_TRAFFIC_MULTIPLIER: 12
shotgun:dot:
<<: *shotgun_job
@@ -1722,7 +1722,7 @@ shotgun:doh-get:
variables:
SHOTGUN_SCENARIO: doh-get
SHOTGUN_TRAFFIC_MULTIPLIER: 3
SHOTGUN_EVAL_THRESHOLD_LATENCY_PCTL_MAX: 0.3 # bump from the default due to increased tail-end jitter
SHOTGUN_EVAL_THRESHOLD_LATENCY_PCTL_MAX: 0.4 # bump from the default due to increased tail-end jitter
rules: *shotgun_rules_manual_mr
.stress-test: &stress_test
+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))))
{
-2
View File
@@ -301,7 +301,6 @@ dnssec-policy \"default\" {\n\
cds-digest-types { 2; };\n\
dnskey-ttl " DNS_KASP_KEY_TTL ";\n\
inline-signing yes;\n\
manual-mode no;\n\
offline-ksk no;\n\
publish-safety " DNS_KASP_PUBLISH_SAFETY "; \n\
retire-safety " DNS_KASP_RETIRE_SAFETY "; \n\
@@ -320,7 +319,6 @@ dnssec-policy \"insecure\" {\n\
max-zone-ttl 0; \n\
keys { };\n\
inline-signing yes;\n\
manual-mode no;\n\
};\n\
\n\
"
-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;
}
}
+7 -1
View File
@@ -129,6 +129,7 @@ static int maxudp = 0;
/*
* -T options:
*/
static bool cookiealwaysvalid = false;
static bool dropedns = false;
static bool ednsformerr = false;
static bool ednsnotimp = false;
@@ -652,7 +653,9 @@ parse_T_opt(char *option) {
* force the server to behave (or misbehave) in
* specified ways for testing purposes.
*/
if (!strcmp(option, "dropedns")) {
if (!strcmp(option, "cookiealwaysvalid")) {
cookiealwaysvalid = true;
} else if (!strcmp(option, "dropedns")) {
dropedns = true;
} else if (!strcmp(option, "ednsformerr")) {
ednsformerr = true;
@@ -1220,6 +1223,9 @@ setup(void) {
/*
* Modify server context according to command line options
*/
if (cookiealwaysvalid) {
ns_server_setoption(sctx, NS_SERVER_COOKIEALWAYSVALID, true);
}
if (disable4) {
ns_server_setoption(sctx, NS_SERVER_DISABLE4, true);
}
+21 -17
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);
/*
@@ -6587,7 +6598,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
* Ensure that zone keys are reloaded on reconfig
*/
if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0) {
dns_zone_rekey(zone, fullsign, false);
dns_zone_rekey(zone, fullsign);
}
cleanup:
@@ -12125,7 +12136,7 @@ named_server_rekey(named_server_t *server, isc_lex_t *lex,
} else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign) {
result = ISC_R_NOPERM;
} else {
dns_zone_rekey(zone, fullsign, false);
dns_zone_rekey(zone, fullsign);
}
dns_zone_detach(&zone);
@@ -14460,8 +14471,6 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
dns_dnsseckey_t *key;
char *ptr, *zonetext = NULL;
const char *msg = NULL;
/* variables for -step */
bool forcestep = false;
/* variables for -checkds */
bool checkds = false, dspublish = false;
/* variables for -rollover */
@@ -14505,8 +14514,6 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
rollover = true;
} else if (strcasecmp(ptr, "-checkds") == 0) {
checkds = true;
} else if (strcasecmp(ptr, "-step") == 0) {
forcestep = true;
} else {
CHECK(DNS_R_SYNTAX);
}
@@ -14663,7 +14670,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
* Rekey after checkds command because the next key
* event may have changed.
*/
dns_zone_rekey(zone, false, false);
dns_zone_rekey(zone, false);
if (use_keyid) {
char tagbuf[6];
@@ -14713,7 +14720,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
* Rekey after rollover command because the next key
* event may have changed.
*/
dns_zone_rekey(zone, false, false);
dns_zone_rekey(zone, false);
if (use_keyid) {
char tagbuf[6];
@@ -14737,10 +14744,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex,
CHECK(putstr(text, isc_result_totext(ret)));
break;
}
} else if (forcestep) {
dns_zone_rekey(zone, false, true);
}
CHECK(putnull(text));
cleanup:
@@ -16210,7 +16214,7 @@ named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
CHECK(putnull(text));
} else {
/* Schedule a rekey */
dns_zone_rekey(zone, false, false);
dns_zone_rekey(zone, false);
}
cleanup:
+2 -2
View File
@@ -1603,7 +1603,7 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) {
isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf));
TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
} else if (is_presoa) {
addr = dns_zone_getsourceaddr(zone);
dns_zone_getsourceaddr(zone, &addr);
isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
} else {
@@ -2660,7 +2660,7 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) {
json_object_object_add(xfrinobj, "localaddr",
json_object_new_string(addr_buf));
} else if (is_presoa) {
addr = dns_zone_getsourceaddr(zone);
dns_zone_getsourceaddr(zone, &addr);
isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
json_object_object_add(xfrinobj, "localaddr",
json_object_new_string(addr_buf));
+6 -8
View File
@@ -1279,22 +1279,22 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
obj = NULL;
result = named_config_get(maps, "parental-source", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
CHECK(dns_zone_setparentalsrc4(zone, cfg_obj_assockaddr(obj)));
dns_zone_setparentalsrc4(zone, cfg_obj_assockaddr(obj));
obj = NULL;
result = named_config_get(maps, "parental-source-v6", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
CHECK(dns_zone_setparentalsrc6(zone, cfg_obj_assockaddr(obj)));
dns_zone_setparentalsrc6(zone, cfg_obj_assockaddr(obj));
obj = NULL;
result = named_config_get(maps, "notify-source", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
CHECK(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj));
obj = NULL;
result = named_config_get(maps, "notify-source-v6", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
CHECK(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj));
obj = NULL;
result = named_config_get(maps, "notify-to-soa", &obj);
@@ -1938,14 +1938,12 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
obj = NULL;
result = named_config_get(maps, "transfer-source", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
CHECK(dns_zone_setxfrsource4(mayberaw,
cfg_obj_assockaddr(obj)));
dns_zone_setxfrsource4(mayberaw, cfg_obj_assockaddr(obj));
obj = NULL;
result = named_config_get(maps, "transfer-source-v6", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
CHECK(dns_zone_setxfrsource6(mayberaw,
cfg_obj_assockaddr(obj)));
dns_zone_setxfrsource6(mayberaw, cfg_obj_assockaddr(obj));
obj = NULL;
(void)named_config_get(maps, "try-tcp-refresh", &obj);
-1
View File
@@ -140,7 +140,6 @@ TESTS = \
redirect \
resolver \
rndc \
rollover \
rootkeysentinel \
rpzextra \
rrchecker \
+1
View File
@@ -28,6 +28,7 @@ options {
} except-from {
"example";
};
qname-minimization disabled; // Regression test for GL #4652
};
trust-anchors { };
-1
View File
@@ -27,7 +27,6 @@ dnssec-policy "test" {
zsk lifetime P30D algorithm 13;
csk key-store "hsm" lifetime P30D algorithm 8 2048;
};
manual-mode no;
max-zone-ttl 86400;
nsec3param ;
parent-ds-ttl 7200;
+4 -2
View File
@@ -131,11 +131,13 @@ status=$((status + ret))
echo_i "checking that log-report-channel zones fail if '*._er/TXT' is missing ($n)"
ret=0
$CHECKZONE -R fail example zones/er.db >test.out2.$n 2>&1 || ret=1
grep -F "no '*._er/TXT' wildcard found" test.out4.$n >/dev/null && ret=1
grep -F "no '*._er/TXT' wildcard found" test.out2.$n >/dev/null && ret=1
$CHECKZONE example zones/er-missing.db >test.out3.$n 2>&1 || ret=1
grep -F "no '*._er/TXT' wildcard found" test.out4.$n >/dev/null && ret=1
grep -F "no '*._er/TXT' wildcard found" test.out3.$n >/dev/null && ret=1
$CHECKZONE -R fail example zones/er-missing.db >test.out4.$n 2>&1 && ret=1
grep -F "no '*._er/TXT' wildcard found" test.out4.$n >/dev/null || ret=1
n=$((n + 1))
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "checking that raw zone with bad class is handled ($n)"
+1
View File
@@ -308,6 +308,7 @@ def logger(request, system_test_name):
@pytest.fixture(scope="module")
def expected_artifacts(request):
common_artifacts = [
"*/.hypothesis", # drop after Ubuntu 20.04 Focal Fossa gets removed from CI
".libs/*", # possible build artifacts, see GL #5055
"ns*/named.conf",
"ns*/named.memstats",
+26 -4
View File
@@ -361,6 +361,23 @@ grep "status: NOERROR," dig.out.test$n >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "Restart NS4 with -T cookiealwaysvalid ($n)"
stop_server ns4
touch ns4/named.cookiealwaysvalid
start_server --noclean --restart --port ${PORT} ns4 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "test NS6 cookie on NS4 with -T cookiealwaysvalid (expect success) ($n)"
ret=0
$DIG $DIGOPTS +cookie=$ns6cookie -b 10.53.0.4 +nobadcookie soa . @10.53.0.4 >dig.out.test$n || ret=1
grep "; COOKIE:.*(good)" dig.out.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.test$n >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "check that test server is correctly configured ($n)"
ret=0
@@ -552,16 +569,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
@@ -19,6 +19,7 @@ pytestmark = pytest.mark.extra_artifacts(
"ans*/ans.run",
"ans*/query.log",
"ns1/named_dump.db*",
"ns4/named.cookiealwaysvalid",
]
)
+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
+3
View File
@@ -30,3 +30,6 @@ ns8 is a caching-only server, configured with unsupported and disabled
algorithms. It is used for testing failure cases.
ns9 is a forwarding-only server.
ans11 is a mocked authoritative server. Used to simulate broken authoritative
server supporting DNSSEC.
+54
View File
@@ -0,0 +1,54 @@
# 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.
from isctest.asyncserver import (
AsyncDnsServer,
DomainHandler,
QueryContext,
ResponseAction,
DnsResponseSend,
)
from typing import AsyncGenerator
import dns
class DnssecManglerHandler(DomainHandler):
domains = ["missingdnskey.example."]
def hide_dnskey(self, qctx: QueryContext) -> None:
qctx.response.answer = []
def add_rrsig(self, qctx: QueryContext) -> None:
rrsig = None
if qctx.qname == qctx.zone.origin:
rrsig = qctx.zone.find_rdataset(
qctx.zone.origin, dns.rdatatype.RRSIG, qctx.qtype, True
)
else:
rrsig = qctx.node.get_rdataset(qctx.qclass, dns.rdatatype.RRSIG, True)
if rrsig:
rrsig_rrset = dns.rrset.RRset(qctx.qname, qctx.qclass, dns.rdatatype.RRSIG)
rrsig_rrset.update(rrsig)
qctx.response.answer.append(rrsig_rrset)
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
if qctx.qtype == dns.rdatatype.DNSKEY:
self.hide_dnskey(qctx)
else:
self.add_rrsig(qctx)
yield DnsResponseSend(qctx.response)
server = AsyncDnsServer()
server.install_response_handler(DnssecManglerHandler())
server.run()
@@ -9,19 +9,16 @@
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns3
ns3 A 10.53.0.3
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2000042407 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
MX 10 mx
ns A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
set -e
echo_i "ans11/sign.sh"
zone=missingdnskey.example.
infile=missingdnskey.example.db.in
zonefile=missingdnskey.example.db
keyname1=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone "$zone")
keyname2=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone -f KSK "$zone")
cat "$infile" "$keyname1.key" "$keyname2.key" >"$zonefile"
"$SIGNER" -o "$zone" "$zonefile" >/dev/null
# AsyncDnsServer expects a file zone name defined as <apexname>.db, so let's
# renamed the signed file.
mv "$zonefile".signed $zonefile
@@ -177,3 +177,6 @@ rsasha1-1024 NS ns.rsasha1-1024
ns.rsasha1-1024 A 10.53.0.3
dname-at-apex-nsec3 NS ns3
missingdnskey NS ns.missingdnskey
ns.missingdnskey A 10.53.0.11
+5 -2
View File
@@ -16,8 +16,9 @@
set -e
# Sign child zones (served by ns3).
# Sign child zones (served by ns3 and ans11).
(cd ../ns3 && $SHELL sign.sh)
(cd ../ans11 && $SHELL sign.sh)
echo_i "ns2/sign.sh"
@@ -64,11 +65,13 @@ 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
cp "../ans11/dsset-missingdnskey.example." .
# Sign the "example." zone.
keyname1=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone -f KSK "$zone")
keyname2=$("$KEYGEN" -q -a "$ALTERNATIVE_ALGORITHM" -b "$ALTERNATIVE_BITS" -n zone "$zone")
@@ -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
+37 -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 -E '^(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"
@@ -4108,6 +4133,16 @@ n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
echo_i "check EDE 9 (Missing DNSKEY) is added when the zone is signed but no DNSKEY is provided ($n)"
ret=0
dig_with_opts @10.53.0.4 missingdnskey.example SOA >dig.out.ns4.test$n
grep "status: SERVFAIL," dig.out.ns4.test$n >/dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n >/dev/null && ret=1
grep "; EDE: 9 (DNSKEY Missing): (missingdnskey.example/DNSKEY)" dig.out.ns4.test$n >/dev/null || ret=1
n=$((n + 1))
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
# The next two queries ensure that a zone signed with a DNSKEY that the nameserver
# has a disabled algorithm match for will yield insecure positive responses.
# These trust anchors in ns8 are ignored and so this domain is treated as insecure.
@@ -156,6 +156,8 @@ pytestmark = pytest.mark.extra_artifacts(
"ns6/optout-tld.db",
"ns7/split-rrsig.db",
"ns7/split-rrsig.db.unsplit",
"ans11/missingdnskey.example.db",
"ans11/missingdnskey.example.db.tmp",
"signer/example.db",
"signer/example.db.after",
"signer/example.db.before",
+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
+100 -32
View File
@@ -224,6 +224,20 @@ class DnsProtocol(enum.Enum):
TCP = enum.auto()
@dataclass(frozen=True)
class Peer:
"""
Pretty-printed connection endpoint.
"""
host: str
port: int
def __str__(self) -> str:
host = f"[{self.host}]" if ":" in self.host else self.host
return f"{host}:{self.port}"
@dataclass
class QueryContext:
"""
@@ -232,7 +246,7 @@ class QueryContext:
query: dns.message.Message
response: dns.message.Message
peer: Tuple[str, int]
peer: Peer
protocol: DnsProtocol
zone: Optional[dns.zone.Zone] = None
soa: Optional[dns.rrset.RRset] = None
@@ -513,56 +527,110 @@ class AsyncDnsServer(AsyncServer):
self._zone_tree.add(zone)
async def _handle_udp(
self, wire: bytes, peer: Tuple[str, int], transport: asyncio.DatagramTransport
self, wire: bytes, addr: Tuple[str, int], transport: asyncio.DatagramTransport
) -> None:
logging.debug("Received UDP message: %s", wire.hex())
peer = Peer(addr[0], addr[1])
responses = self._handle_query(wire, peer, DnsProtocol.UDP)
async for response in responses:
transport.sendto(response, peer)
transport.sendto(response, addr)
async def _handle_tcp(
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
) -> None:
wire_length_bytes = await reader.read(2)
(wire_length,) = struct.unpack("!H", wire_length_bytes)
logging.debug("Receiving TCP message (%d octets)...", wire_length)
peer_info = writer.get_extra_info("peername")
peer = Peer(peer_info[0], peer_info[1])
logging.debug("Accepted TCP connection from %s", peer)
wire = await reader.read(wire_length)
full_message = wire_length_bytes + wire
logging.debug("Received complete TCP message: %s", full_message.hex())
peer = writer.get_extra_info("peername")
responses = self._handle_query(wire, peer, DnsProtocol.TCP)
async for response in responses:
writer.write(response)
while True:
try:
await writer.drain()
wire = await self._read_tcp_query(reader, peer)
if not wire:
break
await self._send_tcp_response(writer, peer, wire)
except ConnectionResetError:
logging.error(
"TCP connection from %s reset by peer", self._format_peer(peer)
)
logging.error("TCP connection from %s reset by peer", peer)
return
logging.debug("Closing TCP connection from %s", peer)
writer.close()
await writer.wait_closed()
def _format_peer(self, peer: Tuple[str, int]) -> str:
host = peer[0]
port = peer[1]
if "::" in host:
host = f"[{host}]"
return f"{host}:{port}"
async def _read_tcp_query(
self, reader: asyncio.StreamReader, peer: Peer
) -> Optional[bytes]:
wire_length = await self._read_tcp_query_wire_length(reader, peer)
if not wire_length:
return None
def _log_query(
self, qctx: QueryContext, peer: Tuple[str, int], protocol: DnsProtocol
return await self._read_tcp_query_wire(reader, peer, wire_length)
async def _read_tcp_query_wire_length(
self, reader: asyncio.StreamReader, peer: Peer
) -> Optional[int]:
logging.debug("Receiving TCP message length from %s...", peer)
wire_length_bytes = await self._read_tcp_octets(reader, peer, 2)
if not wire_length_bytes:
return None
(wire_length,) = struct.unpack("!H", wire_length_bytes)
return wire_length
async def _read_tcp_query_wire(
self, reader: asyncio.StreamReader, peer: Peer, wire_length: int
) -> Optional[bytes]:
logging.debug("Receiving TCP message (%d octets) from %s...", wire_length, peer)
wire = await self._read_tcp_octets(reader, peer, wire_length)
if not wire:
return None
logging.debug("Received complete TCP message from %s: %s", peer, wire.hex())
return wire
async def _read_tcp_octets(
self, reader: asyncio.StreamReader, peer: Peer, expected: int
) -> Optional[bytes]:
buffer = b""
while len(buffer) < expected:
chunk = await reader.read(expected - len(buffer))
if not chunk:
if buffer:
logging.debug(
"Received short TCP message (%d octets) from %s: %s",
len(buffer),
peer,
buffer.hex(),
)
else:
logging.debug("Received disconnect from %s", peer)
return None
logging.debug("Received %d TCP octets from %s", len(chunk), peer)
buffer += chunk
return buffer
async def _send_tcp_response(
self, writer: asyncio.StreamWriter, peer: Peer, wire: bytes
) -> None:
responses = self._handle_query(wire, peer, DnsProtocol.TCP)
async for response in responses:
writer.write(response)
await writer.drain()
def _log_query(self, qctx: QueryContext, peer: Peer, protocol: DnsProtocol) -> None:
logging.info(
"Received %s/%s/%s (ID=%d) query from %s (%s)",
qctx.qname.to_text(omit_final_dot=True),
dns.rdataclass.to_text(qctx.qclass),
dns.rdatatype.to_text(qctx.qtype),
qctx.query.id,
self._format_peer(peer),
peer,
protocol.name,
)
logging.debug(
@@ -573,14 +641,14 @@ class AsyncDnsServer(AsyncServer):
self,
qctx: QueryContext,
response: Optional[Union[dns.message.Message, bytes]],
peer: Tuple[str, int],
peer: Peer,
protocol: DnsProtocol,
) -> None:
if not response:
logging.info(
"Not sending a response to query (ID=%d) from %s (%s)",
qctx.query.id,
self._format_peer(peer),
peer,
protocol.name,
)
return
@@ -606,7 +674,7 @@ class AsyncDnsServer(AsyncServer):
len(response.authority),
len(response.additional),
qctx.query.id,
self._format_peer(peer),
peer,
protocol.name,
)
logging.debug(
@@ -618,13 +686,13 @@ class AsyncDnsServer(AsyncServer):
"Sending response (%d bytes) to a query (ID=%d) from %s (%s)",
len(response),
qctx.query.id,
self._format_peer(peer),
peer,
protocol.name,
)
logging.debug("[OUT] %s", response.hex())
async def _handle_query(
self, wire: bytes, peer: Tuple[str, int], protocol: DnsProtocol
self, wire: bytes, peer: Peer, protocol: DnsProtocol
) -> AsyncGenerator[bytes, None]:
"""
Yield wire data to send as a response over the established transport.
-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'
File diff suppressed because it is too large Load Diff
@@ -89,6 +89,13 @@ zone "unlimited.kasp" {
dnssec-policy "unlimited";
};
/* Manual rollover. */
zone "manual-rollover.kasp" {
type primary;
file "manual-rollover.kasp.db";
dnssec-policy "manual-rollover";
};
/* A zone that inherits dnssec-policy. */
zone "inherit.kasp" {
type primary;
@@ -204,6 +211,25 @@ zone "rumoured.kasp" {
dnssec-policy "rsasha256";
};
/* RFC 8901 Multi-signer Model 2. */
zone "multisigner-model2.kasp" {
type primary;
file "multisigner-model2.kasp.db";
dnssec-policy "multisigner-model2";
allow-update { any; };
};
/*
* A zone that starts with keys that have tags that are
* outside of the desired multi-signer key tag range.
*/
zone "single-to-multisigner.kasp" {
type primary;
file "single-to-multisigner.kasp.db";
dnssec-policy "multisigner-model2";
allow-update { any; };
};
/*
* Different algorithms.
*/
@@ -237,6 +263,17 @@ zone "max-zone-ttl.kasp" {
dnssec-policy "ttl";
};
/*
* Zone for testing GL #2375: Three is a crowd.
*/
zone "three-is-a-crowd.kasp" {
type primary;
file "three-is-a-crowd.kasp.db";
inline-signing yes;
/* Use same policy as KSK rollover test zones. */
dnssec-policy "ksk-doubleksk";
};
/*
* Zones in different signing states.
*/
@@ -312,3 +349,175 @@ zone "zsk-retired.autosign" {
file "zsk-retired.autosign.db";
dnssec-policy "autosign";
};
/*
* Zones for testing enabling DNSSEC.
*/
zone "step1.enable-dnssec.autosign" {
type primary;
file "step1.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step2.enable-dnssec.autosign" {
type primary;
file "step2.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step3.enable-dnssec.autosign" {
type primary;
file "step3.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step4.enable-dnssec.autosign" {
type primary;
file "step4.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
/*
* Zones for testing ZSK Pre-Publication steps.
*/
zone "step1.zsk-prepub.autosign" {
type primary;
file "step1.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step2.zsk-prepub.autosign" {
type primary;
file "step2.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step3.zsk-prepub.autosign" {
type primary;
file "step3.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step4.zsk-prepub.autosign" {
type primary;
file "step4.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step5.zsk-prepub.autosign" {
type primary;
file "step5.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step6.zsk-prepub.autosign" {
type primary;
file "step6.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
/*
* Zones for testing KSK Double-KSK steps.
*/
zone "step1.ksk-doubleksk.autosign" {
type primary;
file "step1.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step2.ksk-doubleksk.autosign" {
type primary;
file "step2.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step3.ksk-doubleksk.autosign" {
type primary;
file "step3.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step4.ksk-doubleksk.autosign" {
type primary;
file "step4.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step5.ksk-doubleksk.autosign" {
type primary;
file "step5.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step6.ksk-doubleksk.autosign" {
type primary;
file "step6.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
/*
* Zones for testing CSK rollover steps.
*/
zone "step1.csk-roll.autosign" {
type primary;
file "step1.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step2.csk-roll.autosign" {
type primary;
file "step2.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step3.csk-roll.autosign" {
type primary;
file "step3.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step4.csk-roll.autosign" {
type primary;
file "step4.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step5.csk-roll.autosign" {
type primary;
file "step5.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step6.csk-roll.autosign" {
type primary;
file "step6.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step7.csk-roll.autosign" {
type primary;
file "step7.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step8.csk-roll.autosign" {
type primary;
file "step8.csk-roll.autosign.db";
dnssec-policy "csk-roll";
};
zone "step1.csk-roll2.autosign" {
type primary;
file "step1.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step2.csk-roll2.autosign" {
type primary;
file "step2.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step3.csk-roll2.autosign" {
type primary;
file "step3.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step4.csk-roll2.autosign" {
type primary;
file "step4.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step5.csk-roll2.autosign" {
type primary;
file "step5.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step6.csk-roll2.autosign" {
type primary;
file "step6.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step7.csk-roll2.autosign" {
type primary;
file "step7.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
@@ -24,3 +24,113 @@ dnssec-policy "autosign" {
zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "enable-dnssec" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 300;
max-zone-ttl PT12H;
zone-propagation-delay PT5M;
retire-safety PT20M;
publish-safety PT5M;
parent-propagation-delay 1h;
parent-ds-ttl 2h;
keys {
csk lifetime unlimited algorithm @DEFAULT_ALGORITHM_NUMBER@;
};
};
dnssec-policy "zsk-prepub" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 3600;
publish-safety P1D;
retire-safety P2D;
purge-keys PT1H;
keys {
ksk key-directory lifetime P2Y algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime P30D algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay PT1H;
max-zone-ttl 1d;
};
dnssec-policy "ksk-doubleksk" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 2h;
publish-safety P1D;
retire-safety P2D;
purge-keys PT1H;
cdnskey no;
keys {
ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay PT1H;
max-zone-ttl 1d;
parent-ds-ttl 3600;
parent-propagation-delay PT1H;
};
dnssec-policy "csk-roll" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
purge-keys PT1H;
cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes
keys {
csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay 1h;
max-zone-ttl P1D;
parent-ds-ttl 1h;
parent-propagation-delay 1h;
};
dnssec-policy "csk-roll2" {
signatures-refresh 12h;
signatures-validity P1D;
signatures-validity-dnskey P1D;
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 1h;
purge-keys 0;
cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes
keys {
csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay PT1H;
max-zone-ttl 1d;
parent-ds-ttl PT1H;
parent-propagation-delay P1W;
};
@@ -23,6 +23,25 @@ dnssec-policy "default-dynamic" {
inline-signing no;
};
dnssec-policy "manual-rollover" {
dnskey-ttl 3600;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "multisigner-model2" {
dnskey-ttl 3600;
inline-signing no;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535;
};
};
dnssec-policy "migrate-to-dnssec-policy" {
dnskey-ttl 1234;
File diff suppressed because it is too large Load Diff
+74
View File
@@ -44,8 +44,82 @@ zone "." {
file "../../_common/root.hint.blackhole";
};
/* This zone switch from dynamic to inline-signing. */
zone "dynamic2inline.kasp" {
type primary;
file "dynamic2inline.kasp.db";
allow-update { any; };
dnssec-policy "default";
};
/* These zones are going insecure. */
zone "step1.going-insecure.kasp" {
type primary;
file "step1.going-insecure.kasp.db";
dnssec-policy "unsigning";
};
zone "step1.going-insecure-dynamic.kasp" {
type primary;
file "step1.going-insecure-dynamic.kasp.db";
dnssec-policy "unsigning";
inline-signing no;
allow-update { any; };
};
zone "step1.going-straight-to-none.kasp" {
type primary;
file "step1.going-straight-to-none.kasp.db";
dnssec-policy "default";
};
zone "step1.going-straight-to-none-dynamic.kasp" {
type primary;
file "step1.going-straight-to-none-dynamic.kasp.db.signed";
inline-signing no;
dnssec-policy "default";
allow-update { any; };
};
/* These are alorithm rollover test zones. */
zone "step1.algorithm-roll.kasp" {
type primary;
file "step1.algorithm-roll.kasp.db";
dnssec-policy "rsasha256";
};
zone "step1.csk-algorithm-roll.kasp" {
type primary;
file "step1.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone example {
type primary;
file "example.db";
dnssec-policy modified;
};
zone longer-lifetime {
type primary;
file "longer-lifetime.db";
dnssec-policy short-lifetime;
};
zone shorter-lifetime {
type primary;
file "shorter-lifetime.db";
dnssec-policy long-lifetime;
};
zone limit-lifetime {
type primary;
file "limit-lifetime.db";
dnssec-policy unlimited-lifetime;
};
zone unlimit-lifetime {
type primary;
file "unlimit-lifetime.db";
dnssec-policy short-lifetime;
};
+153
View File
@@ -43,8 +43,161 @@ zone "." {
file "../../_common/root.hint.blackhole";
};
/* This zone switch from dynamic to inline-signing. */
zone "dynamic2inline.kasp" {
type primary;
file "dynamic2inline.kasp.db";
allow-update { any; };
dnssec-policy "default";
};
/* Zones for testing going insecure. */
zone "step1.going-insecure.kasp" {
type primary;
file "step1.going-insecure.kasp.db";
dnssec-policy "insecure";
};
zone "step2.going-insecure.kasp" {
type primary;
file "step2.going-insecure.kasp.db";
dnssec-policy "insecure";
};
zone "step1.going-insecure-dynamic.kasp" {
type primary;
file "step1.going-insecure-dynamic.kasp.db";
inline-signing no;
dnssec-policy "insecure";
allow-update { any; };
};
zone "step2.going-insecure-dynamic.kasp" {
type primary;
file "step2.going-insecure-dynamic.kasp.db";
inline-signing no;
dnssec-policy "insecure";
allow-update { any; };
};
zone "step1.going-straight-to-none.kasp" {
type primary;
file "step1.going-straight-to-none.kasp.db";
dnssec-policy "none";
};
zone "step1.going-straight-to-none-dynamic.kasp" {
type primary;
file "step1.going-straight-to-none-dynamic.kasp.db.signed";
inline-signing no;
dnssec-policy "none";
allow-update { any; };
};
/*
* Zones for testing KSK/ZSK algorithm roll.
*/
zone "step1.algorithm-roll.kasp" {
type primary;
file "step1.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step2.algorithm-roll.kasp" {
type primary;
file "step2.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step3.algorithm-roll.kasp" {
type primary;
file "step3.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step4.algorithm-roll.kasp" {
type primary;
file "step4.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step5.algorithm-roll.kasp" {
type primary;
file "step5.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step6.algorithm-roll.kasp" {
type primary;
file "step6.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
/*
* Zones for testing CSK algorithm roll.
*/
zone "step1.csk-algorithm-roll.kasp" {
type primary;
file "step1.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step2.csk-algorithm-roll.kasp" {
type primary;
file "step2.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step3.csk-algorithm-roll.kasp" {
type primary;
file "step3.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step4.csk-algorithm-roll.kasp" {
type primary;
file "step4.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step5.csk-algorithm-roll.kasp" {
type primary;
file "step5.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step6.csk-algorithm-roll.kasp" {
type primary;
file "step6.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone example {
type primary;
file "example.db";
dnssec-policy modified;
};
zone longer-lifetime {
type primary;
file "longer-lifetime.db";
dnssec-policy long-lifetime;
};
zone shorter-lifetime {
type primary;
file "shorter-lifetime.db";
dnssec-policy short-lifetime;
};
zone limit-lifetime {
type primary;
file "limit-lifetime.db";
dnssec-policy short-lifetime;
};
zone unlimit-lifetime {
type primary;
file "unlimit-lifetime.db";
dnssec-policy unlimited-lifetime;
};
@@ -11,6 +11,15 @@
* information regarding copyright ownership.
*/
dnssec-policy "unsigning" {
dnskey-ttl 7200;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "nsec3" {
nsec3param iterations 0 optout no salt-length 0;
};
@@ -37,3 +46,41 @@ dnssec-policy "long-lifetime" {
csk lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "rsasha256" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
ksk lifetime unlimited algorithm rsasha256;
zsk lifetime unlimited algorithm rsasha256;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
dnssec-policy "ecdsa256" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
ksk lifetime unlimited algorithm ecdsa256;
zsk lifetime unlimited algorithm ecdsa256;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
+402
View File
@@ -16,8 +16,410 @@
echo_i "ns6/setup.sh"
setup() {
zone="$1"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
}
# Make lines shorter by storing key states in environment variables.
H="HIDDEN"
R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
for zn in shorter-lifetime longer-lifetime limit-lifetime unlimit-lifetime; do
setup $zn
cp template.db.in $zonefile
done
# The child zones (step1, step2) beneath these zones represent the various
# steps of unsigning a zone.
for zn in going-insecure.kasp going-insecure-dynamic.kasp; do
# Step 1:
# Set up a zone with dnssec-policy that is going insecure.
setup step1.$zn
echo "$zone" >>zones
T="now-10d"
ksktimes="-P $T -A $T -P sync $T"
zsktimes="-P $T -A $T"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.2)
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# Set up a zone with dnssec-policy that is going insecure. Don't add
# this zone to the zones file, because this zone is no longer expected
# to be fully signed.
setup step2.$zn
# The DS was withdrawn from the parent zone 26 hours ago.
Trem="now-26h"
ksktimes="-P $T -A $T -P sync $T"
zsktimes="-P $T -A $T"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $T -r $O $T -d $U $Trem -D ds $Trem "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK}.state"
echo "Lifetime: 5184000" >>"${ZSK}.state"
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
done
# This zone is going straight to "none" policy. This is undefined behavior.
setup step1.going-straight-to-none.kasp
echo "$zone" >>zones
TactN="now"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
CSK=$($KEYGEN -k default $csktimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $O $TactN -z $O $TactN -r $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -z -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# This zone is going straight to "none" policy. This is undefined behavior.
setup step1.going-straight-to-none-dynamic.kasp
echo "$zone" >>zones
TactN="now"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
CSK=$($KEYGEN -k default $csktimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $O $TactN -z $O $TactN -r $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -z -x -s now-1h -e now+2w -o $zone -O full -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
#
# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
# algorithm rollover.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.algorithm-roll.kasp
echo "$zone" >>zones
TactN="now"
ksktimes="-P ${TactN} -A ${TactN} -P sync ${TactN}"
zsktimes="-P ${TactN} -A ${TactN}"
KSK=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a RSASHA256 -L 3600 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone 8 "$KSK" >>"$infile"
private_type_record $zone 8 "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# After the publication interval has passed the DNSKEY is OMNIPRESENT.
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 + 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}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# 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 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}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 4:
# 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-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}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -D ds $TactN1 "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TactN1 -P ds $TactN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 5:
# 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-40h"
TretN="now-37h"
TremN="now-2h"
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}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TactN1 "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $U $TremN -z $U $TremN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TactN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 6:
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.algorithm-roll.kasp
# Additional time passed: 7h.
TactN="now-47h"
TretN="now-44h"
TremN="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}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $H $TremN -r $U $TdeaN -d $H $TactN1 "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $H $TremN -z $U $TdeaN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TactN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
#
# The zones at csk-algorithm-roll.kasp represent the various steps of a CSK
# algorithm rollover.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.csk-algorithm-roll.kasp
echo "$zone" >>zones
TactN="now"
csktimes="-P ${TactN} -P sync ${TactN} -A ${TactN}"
CSK=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" >"$infile"
private_type_record $zone 5 "$CSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# After the publication interval has passed the DNSKEY is OMNIPRESENT.
setup step2.csk-algorithm-roll.kasp
# The time passed since the new algorithm keys have been introduced is 3 hours.
TactN="now-3h"
TpubN1="now-3h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now"
newtimes="-P ${TpubN1} -A ${TpubN1}"
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# 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 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)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 4:
# 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-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}"
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $R $TsubN1 -P ds $TsubN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 5:
# 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-40h"
TretN="now-37h"
TremN="now-2h"
TpubN1="now-40h"
TactN1="now-37h"
TsubN1="now-31h"
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)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $U $TremN -r $U $TremN -z $U $TremN -d $H $TremN "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TremN "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 6:
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.csk-algorithm-roll.kasp
# Additional time passed: 7h.
TactN="now-47h"
TretN="now-44h"
TdeaN="now-9h"
TremN="now-7h"
TpubN1="now-47h"
TactN1="now-44h"
TsubN1="now-38h"
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)
CSK2=$($KEYGEN -k csk-algoroll -l policies/csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $H $TremN -r $U $TdeaN -z $U $TdeaN -d $H $TactN1 "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TactN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
#
# Reload testing
#
echo "example" >>zones
cp example.db.in example.db
setup "dynamic2inline.kasp"
cp template.db.in $zonefile
-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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
# 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 pytest
pytestmark = pytest.mark.extra_artifacts(
[
"K*.private",
"K*.key",
"K*.state",
"K*.cmp",
"*.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*.private",
"ns*/K*.key",
"ns*/K*.state",
"ns*/*.db",
"ns*/*.db.infile",
"ns*/*.db.signed",
"ns*/*.jbk",
"ns*/*.jnl",
"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",
"ns*/*.zsk1",
"ns*/*.zsk2",
"ns3/legacy-keys.*",
"ns3/dynamic-signed-inline-signing.kasp.db.signed.signed",
]
)
def test_kasp(run_tests_sh):
run_tests_sh()
+71 -45
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):
@@ -669,9 +695,9 @@ def test_ksr_common(servers):
# - check keys
check_keys(overlapping_zsks, lifetime, with_state=True)
# - check apex
isctest.kasp.check_apex(ns1, zone, ksks, overlapping_zsks, offline_ksk=True)
isctest.kasp.check_apex(ns1, zone, ksks, overlapping_zsks)
# - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, overlapping_zsks, offline_ksk=True)
isctest.kasp.check_subdomain(ns1, zone, ksks, overlapping_zsks)
def test_ksr_lastbundle(servers):
@@ -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)
@@ -744,9 +770,9 @@ def test_ksr_lastbundle(servers):
# - check keys
check_keys(zsks, lifetime, offset=offset, with_state=True)
# - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
# - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
# check that last bundle warning is logged
warning = "last bundle in skr, please import new skr file"
@@ -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)
@@ -824,9 +850,9 @@ def test_ksr_inthemiddle(servers):
# - check keys
check_keys(zsks, lifetime, offset=offset, with_state=True)
# - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
# - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
# check that no last bundle warning is logged
warning = "last bundle in skr, please import new skr file"
@@ -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
@@ -1019,9 +1045,9 @@ def test_ksr_unlimited(servers):
# - check keys
check_keys(zsks, lifetime, with_state=True)
# - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
# - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
def test_ksr_twotone(servers):
@@ -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
@@ -1137,9 +1163,9 @@ def test_ksr_twotone(servers):
lifetime = timedelta(days=31 * 5)
check_keys(zsks_altalg, lifetime, alg, size, with_state=True)
# - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
# - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
def test_ksr_kskroll(servers):
@@ -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)
@@ -1211,6 +1237,6 @@ def test_ksr_kskroll(servers):
# - check keys
check_keys(zsks, None, with_state=True)
# - check apex
isctest.kasp.check_apex(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_apex(ns1, zone, ksks, zsks)
# - check subdomain
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks, offline_ksk=True)
isctest.kasp.check_subdomain(ns1, zone, ksks, zsks)
+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))
@@ -9,19 +9,9 @@
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
@ 30 SOA ns2.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns2.good.
NS ns6
ns6 A 10.53.0.6
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3
8.2.6.0 60 NS ns3.good.
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 PTR nee.com.
+91 -436
View File
@@ -1,456 +1,111 @@
# 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.
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
SPDX-License-Identifier: MPL-2.0
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
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.
"""
from typing import AsyncGenerator
import dns.message
import dns.name
import dns.rcode
import dns.rdataclass
import dns.rdatatype
from isctest.asyncserver import (
AsyncDnsServer,
DnsResponseSend,
DomainHandler,
QueryContext,
ResponseAction,
)
from qmin_ans import (
DelayedResponseHandler,
EntRcodeChanger,
QueryLogHandler,
log_query,
)
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
class QueryLogger(QueryLogHandler):
domains = ["1.0.0.2.ip6.arpa.", "fwd.", "good."]
def endswith(domain, labels):
return domain.endswith("." + labels) or domain == labels
class BadHandler(EntRcodeChanger):
domains = ["bad."]
rcode = dns.rcode.NXDOMAIN
############################################################################
# Respond to a DNS query.
# For good. it serves:
# ns2.good. IN A 10.53.0.2
# zoop.boing.good. NS ns3.good.
# ns3.good. IN A 10.53.0.3
# too.many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.good. A 192.0.2.2
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 milliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage to non-empty terminals
#
# For 1.0.0.2.ip6.arpa it serves
# 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. IN PTR nee.com.
# 8.2.6.0.1.0.0.2.ip6.arpa IN NS ns3.good
# 1.0.0.2.ip6.arpa. IN NS ns2.good
# ip6.arpa. IN NS ns2.good
#
# For stale. it serves:
# a.b. NS ns.a.b.stale.
# ns.a.b.stale. IN A 10.53.0.3
# b. NS ns.b.stale.
# ns.b.stale. IN A 10.53.0.4
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split(".")
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
ugly = False
slow = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
if endswith(lqname, "1.0.0.2.ip6.arpa."):
# Direct query - give direct answer
if endswith(lqname, "8.2.6.0.1.0.0.2.ip6.arpa."):
# Delegate to ns3
r.authority.append(
dns.rrset.from_text(
"8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, NS, "ns3.good."
)
)
r.additional.append(
dns.rrset.from_text("ns3.good.", 60, IN, A, "10.53.0.3")
)
elif (
lqname
== "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."
and rrtype == PTR
):
# Direct query - give direct answer
r.answer.append(
dns.rrset.from_text(
"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.",
1,
IN,
PTR,
"nee.com.",
)
)
r.flags |= dns.flags.AA
elif lqname == "1.0.0.2.ip6.arpa." and rrtype == NS:
# NS query at the apex
r.answer.append(
dns.rrset.from_text("1.0.0.2.ip6.arpa.", 30, IN, NS, "ns2.good.")
)
r.flags |= dns.flags.AA
elif endswith(
"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.",
lqname,
):
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"1.0.0.2.ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"1.0.0.2.ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
r.set_rcode(NXDOMAIN)
return r
elif endswith(lqname, "ip6.arpa."):
if lqname == "ip6.arpa." and rrtype == NS:
# NS query at the apex
r.answer.append(dns.rrset.from_text("ip6.arpa.", 30, IN, NS, "ns2.good."))
r.flags |= dns.flags.AA
elif endswith("1.0.0.2.ip6.arpa.", lqname):
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
r.set_rcode(NXDOMAIN)
return r
elif endswith(lqname, "stale."):
if endswith(lqname, "a.b.stale."):
# Delegate to ns.a.b.stale.
r.authority.append(
dns.rrset.from_text("a.b.stale.", 2, IN, NS, "ns.a.b.stale.")
)
r.additional.append(
dns.rrset.from_text("ns.a.b.stale.", 2, IN, A, "10.53.0.3")
)
elif endswith(lqname, "b.stale."):
# Delegate to ns.b.stale.
r.authority.append(
dns.rrset.from_text("b.stale.", 2, IN, NS, "ns.b.stale.")
)
r.additional.append(
dns.rrset.from_text("ns.b.stale.", 2, IN, A, "10.53.0.4")
)
elif lqname == "stale." and rrtype == NS:
# NS query at the apex.
r.answer.append(dns.rrset.from_text("stale.", 2, IN, NS, "ns2.stale."))
r.flags |= dns.flags.AA
elif lqname == "stale." and rrtype == SOA:
# SOA query at the apex.
r.answer.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.stale. 1 2 3 4 5"
)
)
r.flags |= dns.flags.AA
elif lqname == "stale.":
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"
)
)
r.flags |= dns.flags.AA
elif lqname == "ns2.stale.":
if rrtype == A:
r.additional.append(
dns.rrset.from_text("ns.b.stale.", 2, IN, A, "10.53.0.2")
)
else:
r.authority.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"
)
)
r.flags |= dns.flags.AA
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"
)
)
r.set_rcode(NXDOMAIN)
return r
elif endswith(lqname, "bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif endswith(lqname, "ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif endswith(lqname, "good."):
suffix = "good."
lqname = lqname[:-5]
elif endswith(lqname, "slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
elif endswith(lqname, "fwd."):
suffix = "fwd."
lqname = lqname[:-4]
else:
r.set_rcode(REFUSED)
return r
# Good/bad/ugly differs only in how we treat non-empty terminals
if endswith(lqname, "zoop.boing."):
r.authority.append(
dns.rrset.from_text("zoop.boing." + suffix, 1, IN, NS, "ns3." + suffix)
)
elif (
lqname == "many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z."
and rrtype == A
):
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.2"))
r.flags |= dns.flags.AA
elif lqname == "" and rrtype == NS:
r.answer.append(dns.rrset.from_text(suffix, 30, IN, NS, "ns2." + suffix))
r.flags |= dns.flags.AA
elif lqname == "ns2.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns2." + suffix, 30, IN, A, "10.53.0.2")
)
elif rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"ns2." + suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::2"
)
)
else:
r.authority.append(
dns.rrset.from_text(
suffix,
30,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
elif lqname == "ns3.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns3." + suffix, 30, IN, A, "10.53.0.3")
)
elif lqname == "ns3." and rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"ns3." + suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::3"
)
)
else:
r.authority.append(
dns.rrset.from_text(
suffix,
30,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
elif lqname == "ns4.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns4." + suffix, 30, IN, A, "10.53.0.4")
)
elif rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"ns4." + suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::4"
)
)
else:
r.authority.append(
dns.rrset.from_text(
suffix,
30,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
elif lqname == "a.bit.longer.ns.name." and rrtype == A:
r.answer.append(
dns.rrset.from_text("a.bit.longer.ns.name." + suffix, 1, IN, A, "10.53.0.4")
)
r.flags |= dns.flags.AA
elif lqname == "a.bit.longer.ns.name." and rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"a.bit.longer.ns.name." + suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::4"
)
)
r.flags |= dns.flags.AA
else:
r.authority.append(
dns.rrset.from_text(
suffix,
1,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
if bad or not (
endswith("icky.icky.icky.ptang.zoop.boing.", lqname)
or endswith(
"many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.",
lqname,
)
or endswith("a.bit.longer.ns.name.", lqname)
):
r.set_rcode(NXDOMAIN)
if ugly:
r.set_rcode(FORMERR)
if slow:
time.sleep(0.2)
return r
class UglyHandler(EntRcodeChanger):
domains = ["ugly."]
rcode = dns.rcode.FORMERR
def sigterm(signum, frame):
print("Shutting down now...")
os.remove("ans.pid")
running = False
sys.exit(0)
class SlowHandler(DelayedResponseHandler):
domains = ["slow."]
delay = 0.2
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.2"
ip6 = "fd92:7065:b8e:ffff::2"
def send_delegation(
qctx: QueryContext, zone_cut: dns.name.Name, target_addr: str
) -> ResponseAction:
"""
Delegate `zone_cut` to a single in-bailiwick name server, `ns.<zone_cut>`,
with a single IPv4 glue record (provided in `target_addr`) included in the
ADDITIONAL section.
"""
ns_name = "ns." + zone_cut.to_text()
ns_rrset = dns.rrset.from_text(
zone_cut, 2, dns.rdataclass.IN, dns.rdatatype.NS, ns_name
)
a_rrset = dns.rrset.from_text(
ns_name, 2, dns.rdataclass.IN, dns.rdatatype.A, target_addr
)
try:
port = int(os.environ["PORT"])
except:
port = 5300
response = dns.message.make_response(qctx.query)
response.set_rcode(dns.rcode.NOERROR)
response.authority.append(ns_rrset)
response.additional.append(a_rrset)
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
return DnsResponseSend(response, authoritative=False)
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
class StaleHandler(DomainHandler):
"""
`a.b.stale` is a subdomain of `b.stale` and these two subdomains need to be
delegated to different name servers. Therefore, their delegations cannot
be placed in the zone file because the zone cut at `b.stale` would occlude
the one at `a.b.stale`. Generate these delegations dynamically depending
on the QNAME.
"""
f = open("ans.pid", "w")
pid = os.getpid()
print(pid, file=f)
f.close()
domains = ["stale."]
running = True
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
a_b_stale = dns.name.from_text("a.b.stale.")
b_stale = dns.name.from_text("b.stale.")
if qctx.qname.is_subdomain(a_b_stale):
yield send_delegation(qctx, a_b_stale, "10.53.0.3")
elif qctx.qname.is_subdomain(b_stale):
yield send_delegation(qctx, b_stale, "10.53.0.4")
print("Listening on %s port %d" % (ip4, port))
if havev6:
print("Listening on %s port %d" % (ip6, port))
print("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print(
"Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
)
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break
if __name__ == "__main__":
server = AsyncDnsServer()
server.install_response_handler(QueryLogger())
server.install_response_handler(BadHandler())
server.install_response_handler(UglyHandler())
server.install_response_handler(SlowHandler())
server.install_response_handler(StaleHandler())
server.run()
+1
View File
@@ -0,0 +1 @@
good.db
+1
View File
@@ -0,0 +1 @@
good.db
+26
View File
@@ -0,0 +1,26 @@
; 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.
@ 1 SOA ns2 hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns2
ns2 30 A 10.53.0.2
30 AAAA fd92:7065:b8e:ffff::2
zoop.boing 30 NS ns3
ns3 30 A 10.53.0.3
30 AAAA fd92:7065:b8e:ffff::3
ns4 30 A 10.53.0.4
30 AAAA fd92:7065:b8e:ffff::4
a.bit.longer.ns.name 1 A 10.53.0.4
1 AAAA fd92:7065:b8e:ffff::4
+1
View File
@@ -0,0 +1 @@
good.db
+15
View File
@@ -0,0 +1,15 @@
; 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.
@ 2 SOA ns2 hostmaster.stale. 1 2 3 4 5
@ 2 NS ns2
ns2 2 A 10.53.0.2
2 AAAA fd92:7065:b8e:ffff::2
+1
View File
@@ -0,0 +1 @@
good.db
@@ -0,0 +1,15 @@
; 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.
@ 30 SOA ns3.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns3.good.
1.1.1.1 60 NS ns4.good.
+15
View File
@@ -0,0 +1,15 @@
; 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.
@ 1 SOA ns hostmaster.a.b.stale. 1 2 3 4 5
@ 1 NS ns
@ 1 TXT "peekaboo"
ns 1 A 10.53.0.3
+34 -273
View File
@@ -1,285 +1,46 @@
# 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.
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
SPDX-License-Identifier: MPL-2.0
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
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 dns.rcode
from isctest.asyncserver import AsyncDnsServer
from qmin_ans import DelayedResponseHandler, EntRcodeChanger, QueryLogHandler
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
class QueryLogger(QueryLogHandler):
domains = ["8.2.6.0.1.0.0.2.ip6.arpa.", "a.b.stale.", "zoop.boing.good."]
def endswith(domain, labels):
return domain.endswith("." + labels) or domain == labels
class ZoopBoingBadHandler(EntRcodeChanger):
domains = ["zoop.boing.bad."]
rcode = dns.rcode.NXDOMAIN
############################################################################
# Respond to a DNS query.
# For good. it serves:
# zoop.boing.good. NS ns3.good.
# icky.ptang.zoop.boing.good. NS a.bit.longer.ns.name.good.
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 milliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage to non-empty terminals
#
# For stale. it serves:
# a.b.stale. IN TXT peekaboo (resolver did not do qname minimization)
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split(".")
suffix = ""
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
ugly = False
slow = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
ip6req = False
if endswith(lqname, "bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif endswith(lqname, "ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif endswith(lqname, "good."):
suffix = "good."
lqname = lqname[:-5]
elif endswith(lqname, "slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
elif endswith(lqname, "8.2.6.0.1.0.0.2.ip6.arpa."):
ip6req = True
elif endswith(lqname, "a.b.stale."):
if lqname == "a.b.stale.":
r.flags |= dns.flags.AA
if rrtype == TXT:
# Direct query.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "peekaboo"))
elif rrtype == NS:
# NS a.b.
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")
)
elif rrtype == SOA:
# SOA a.b.
r.answer.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
elif lqname == "ns.a.b.stale.":
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")
)
else:
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
else:
r.flags |= dns.flags.AA
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
r.set_rcode(NXDOMAIN)
# NXDOMAIN.
return r
else:
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
if lqname == "zoop.boing." and rrtype == NS:
r.answer.append(
dns.rrset.from_text(lqname + suffix, 1, IN, NS, "ns3." + suffix)
)
r.flags |= dns.flags.AA
elif endswith(lqname, "icky.ptang.zoop.boing."):
r.authority.append(
dns.rrset.from_text(
"icky.ptang.zoop.boing." + suffix,
1,
IN,
NS,
"a.bit.longer.ns.name." + suffix,
)
)
elif endswith("icky.ptang.zoop.boing.", lqname):
r.authority.append(
dns.rrset.from_text(
"zoop.boing." + suffix,
1,
IN,
SOA,
"ns3." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
if bad:
r.set_rcode(NXDOMAIN)
if ugly:
r.set_rcode(FORMERR)
elif endswith(lqname, "zoop.boing."):
r.authority.append(
dns.rrset.from_text(
"zoop.boing." + suffix,
1,
IN,
SOA,
"ns3." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
r.set_rcode(NXDOMAIN)
elif ip6req:
r.authority.append(
dns.rrset.from_text(
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, NS, "ns4.good."
)
)
r.additional.append(dns.rrset.from_text("ns4.good.", 60, IN, A, "10.53.0.4"))
else:
r.set_rcode(REFUSED)
if slow:
time.sleep(0.4)
return r
class ZoopBoingUglyHandler(EntRcodeChanger):
domains = ["zoop.boing.ugly."]
rcode = dns.rcode.FORMERR
def sigterm(signum, frame):
print("Shutting down now...")
os.remove("ans.pid")
running = False
sys.exit(0)
class ZoopBoingSlowHandler(DelayedResponseHandler):
domains = ["zoop.boing.slow."]
delay = 0.4
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.3"
ip6 = "fd92:7065:b8e:ffff::3"
try:
port = int(os.environ["PORT"])
except:
port = 5300
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
f = open("ans.pid", "w")
pid = os.getpid()
print(pid, file=f)
f.close()
running = True
print("Listening on %s port %d" % (ip4, port))
if havev6:
print("Listening on %s port %d" % (ip6, port))
print("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print(
"Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
)
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break
if __name__ == "__main__":
server = AsyncDnsServer()
server.install_response_handler(QueryLogger())
server.install_response_handler(ZoopBoingBadHandler())
server.install_response_handler(ZoopBoingUglyHandler())
server.install_response_handler(ZoopBoingSlowHandler())
server.run()
@@ -0,0 +1,14 @@
; 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.
@ 1 SOA ns3.bad. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.bad.
icky.ptang 1 NS a.bit.longer.ns.name.bad.
@@ -0,0 +1,14 @@
; 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.
@ 1 SOA ns3.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.good.
icky.ptang 1 NS a.bit.longer.ns.name.good.
@@ -0,0 +1,14 @@
; 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.
@ 1 SOA ns3.slow. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.slow.
icky.ptang 1 NS a.bit.longer.ns.name.slow.
@@ -0,0 +1,14 @@
; 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.
@ 1 SOA ns3.ugly. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.ugly.
icky.ptang 1 NS a.bit.longer.ns.name.ugly.
@@ -0,0 +1,15 @@
; 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.
@ 30 SOA ns4.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns4.good.
test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4 1 TXT "long_ip6_name"
+15
View File
@@ -0,0 +1,15 @@
; 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.
@ 1 SOA ns hostmaster.a.b.stale. 1 2 3 4 5
@ 1 NS ns
ns 1 A 10.53.0.4
@ 1 TXT "hooray"
+79 -330
View File
@@ -1,344 +1,93 @@
# 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.
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
SPDX-License-Identifier: MPL-2.0
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
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.
"""
from typing import AsyncGenerator
import dns.rcode
from isctest.asyncserver import (
AsyncDnsServer,
DnsResponseSend,
DomainHandler,
QueryContext,
ResponseAction,
)
from qmin_ans import DelayedResponseHandler, EntRcodeChanger, QueryLogHandler, log_query
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
class QueryLogger(QueryLogHandler):
domains = [
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
"icky.ptang.zoop.boing.good.",
]
def endswith(domain, labels):
return domain.endswith("." + labels) or domain == labels
class StaleHandler(DomainHandler):
"""
The test code relies on this server returning non-minimal (i.e. including
address records in the ADDITIONAL section) responses to NS queries for
`b.stale` and `a.b.stale`. While this logic (returning non-minimal
responses to NS queries) could be implemented in AsyncDnsServer itself,
doing so breaks a lot of other checks in this system test. Therefore, only
these two zones behave in this particular way, thanks to a custom response
handler implemented below.
"""
domains = ["b.stale", "a.b.stale"]
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
if qctx.qtype == dns.rdatatype.NS:
assert qctx.zone
assert qctx.response.answer[0]
for nameserver in qctx.response.answer[0]:
if not nameserver.target.is_subdomain(qctx.response.answer[0].name):
continue
glue_a = qctx.zone.get_rrset(nameserver.target, dns.rdatatype.A)
if glue_a:
qctx.response.additional.append(glue_a)
glue_aaaa = qctx.zone.get_rrset(nameserver.target, dns.rdatatype.AAAA)
if glue_aaaa:
qctx.response.additional.append(glue_aaaa)
yield DnsResponseSend(qctx.response)
############################################################################
# Respond to a DNS query.
# For good. it serves:
# icky.ptang.zoop.boing.good. NS a.bit.longer.ns.name.
# icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.1
# more.icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.2
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 milliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage to non-empty terminals
#
# For stale. it serves:
# a.b.stale. IN TXT hooray (resolver did do qname minimization)
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split(".")
suffix = ""
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
slow = False
ugly = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
ip6req = False
if endswith(lqname, "bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif endswith(lqname, "ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif endswith(lqname, "good."):
suffix = "good."
lqname = lqname[:-5]
elif endswith(lqname, "slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
elif endswith(lqname, "1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."):
ip6req = True
elif endswith(lqname, "b.stale."):
if lqname == "a.b.stale.":
r.flags |= dns.flags.AA
if rrtype == TXT:
# Direct query.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "hooray"))
elif rrtype == NS:
# NS a.b.
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")
)
elif rrtype == SOA:
# SOA a.b.
r.answer.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
elif lqname == "ns.a.b.stale.":
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")
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
elif lqname == "b.stale.":
r.flags |= dns.flags.AA
if rrtype == NS:
# NS b.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.b.stale."))
r.additional.append(
dns.rrset.from_text("ns.b.stale.", 1, IN, A, "10.53.0.4")
)
elif rrtype == SOA:
# SOA b.
r.answer.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
elif lqname == "ns.b.stale.":
r.flags |= dns.flags.AA
if rrtype == A:
# SOA a.b.
r.answer.append(
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
else:
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
r.set_rcode(NXDOMAIN)
# NXDOMAIN.
return r
else:
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
if lqname == "icky.icky.icky.ptang.zoop.boing." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.1"))
r.flags |= dns.flags.AA
elif lqname == "more.icky.icky.icky.ptang.zoop.boing." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.2"))
r.flags |= dns.flags.AA
elif lqname == "icky.ptang.zoop.boing." and rrtype == NS:
r.answer.append(
dns.rrset.from_text(
lqname + suffix, 1, IN, NS, "a.bit.longer.ns.name." + suffix
)
)
r.flags |= dns.flags.AA
elif endswith(lqname, "icky.ptang.zoop.boing."):
r.authority.append(
dns.rrset.from_text(
"icky.ptang.zoop.boing." + suffix,
1,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
if bad or not endswith("more.icky.icky.icky.ptang.zoop.boing.", lqname):
r.set_rcode(NXDOMAIN)
if ugly:
r.set_rcode(FORMERR)
elif ip6req:
r.flags |= dns.flags.AA
if (
lqname
== "test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."
and rrtype == TXT
):
r.answer.append(
dns.rrset.from_text(
"test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
1,
IN,
TXT,
"long_ip6_name",
)
)
elif endswith(
"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
lqname,
):
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
60,
IN,
SOA,
"ns4.good. hostmaster.arpa. 2018050100 120 30 320 16",
)
)
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
60,
IN,
SOA,
"ns4.good. hostmaster.arpa. 2018050100 120 30 320 16",
)
)
r.set_rcode(NXDOMAIN)
else:
r.set_rcode(REFUSED)
if slow:
time.sleep(0.4)
return r
class IckyPtangZoopBoingBadHandler(EntRcodeChanger):
domains = ["icky.ptang.zoop.boing.bad."]
rcode = dns.rcode.NXDOMAIN
def sigterm(signum, frame):
print("Shutting down now...")
os.remove("ans.pid")
running = False
sys.exit(0)
class IckyPtangZoopBoingUglyHandler(EntRcodeChanger):
domains = ["icky.ptang.zoop.boing.ugly."]
rcode = dns.rcode.FORMERR
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.4"
ip6 = "fd92:7065:b8e:ffff::4"
class IckyPtangZoopBoingSlowHandler(DelayedResponseHandler):
domains = ["icky.ptang.zoop.boing.slow."]
delay = 0.4
try:
port = int(os.environ["PORT"])
except:
port = 5300
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
f = open("ans.pid", "w")
pid = os.getpid()
print(pid, file=f)
f.close()
running = True
print("Listening on %s port %d" % (ip4, port))
if havev6:
print("Listening on %s port %d" % (ip6, port))
print("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print(
"Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
)
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break
if __name__ == "__main__":
server = AsyncDnsServer()
server.install_response_handler(QueryLogger())
server.install_response_handler(StaleHandler())
server.install_response_handler(IckyPtangZoopBoingBadHandler())
server.install_response_handler(IckyPtangZoopBoingUglyHandler())
server.install_response_handler(IckyPtangZoopBoingSlowHandler())
server.run()
+16
View File
@@ -0,0 +1,16 @@
; 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.
@ 1 SOA ns hostmaster.b.stale. 1 2 3 4 5
@ 1 NS ns
ns 1 A 10.53.0.4
a 1 NS ns.a
ns.a 1 A 10.53.0.4
@@ -0,0 +1,15 @@
; 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.
@ 1 SOA ns4.bad. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.bad.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
@@ -0,0 +1,15 @@
; 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.
@ 1 SOA ns4.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.good.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
@@ -0,0 +1,15 @@
; 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.
@ 1 SOA ns4.slow. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.slow.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
@@ -0,0 +1,15 @@
; 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.
@ 1 SOA ns4.ugly. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.ugly.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
+107
View File
@@ -0,0 +1,107 @@
"""
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.
"""
from typing import AsyncGenerator
import abc
import dns.rcode
import dns.rdataclass
import dns.rdatatype
from isctest.asyncserver import (
DnsResponseSend,
DomainHandler,
QueryContext,
ResponseAction,
)
from isctest.compat import dns_rcode
def log_query(qctx: QueryContext) -> None:
"""
Log a received DNS query to a text file inspected by `tests.sh`. AAAA and
A queries are logged identically because the relative order in which they
are received does not matter.
"""
qname = qctx.qname.to_text()
qtype = dns.rdatatype.to_text(qctx.qtype)
if qtype in ("A", "AAAA"):
qtype = "ADDR"
with open("query.log", "a", encoding="utf-8") as query_log:
print(f"{qtype} {qname}", file=query_log)
class QueryLogHandler(DomainHandler):
"""
Log all received DNS queries to a text file. Use the zone file for
preparing responses.
"""
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
yield DnsResponseSend(qctx.response)
class EntRcodeChanger(DomainHandler):
"""
Log all received DNS queries to a text file. Use the zone file for
preparing responses, but override the RCODE returned for empty
non-terminals (ENTs) to the value specified by the child class. This
emulates broken authoritative servers.
"""
@property
@abc.abstractmethod
def rcode(self) -> dns_rcode:
raise NotImplementedError
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
assert qctx.zone
log_query(qctx)
if (
qctx.response.rcode() == dns.rcode.NOERROR
and not qctx.response.answer
and qctx.response.authority
and qctx.response.authority[0].rdtype == dns.rdatatype.SOA
and not qctx.zone.get_node(qctx.qname)
):
qctx.response.set_rcode(self.rcode)
yield DnsResponseSend(qctx.response)
class DelayedResponseHandler(DomainHandler):
"""
Log all received DNS queries to a text file. Use the zone file for
preparing responses, but delay sending every answer by the amount of time
specified (in seconds) by the child class. This emulates network delays.
"""
@property
@abc.abstractmethod
def delay(self) -> float:
raise NotImplementedError
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
yield DnsResponseSend(qctx.response, delay=self.delay)
+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
@@ -11,20 +11,14 @@
* information regarding copyright ownership.
*/
dnssec-policy "csk-algoroll" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
csk lifetime unlimited algorithm rsasha256;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
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)
+33 -4
View File
@@ -43,6 +43,12 @@ grep "status: NOERROR" dig.out.ns1.test${n} >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
rndccmd 10.53.0.1 stats || ret=1 # Get the responses, RTT and timeout statistics before the following timeout tests
grep -F 'responses received' ns1/named.stats >ns1/named.stats.responses-before || true
grep -F 'queries with RTT' ns1/named.stats >ns1/named.stats.rtt-before || true
grep -F 'query timeouts' ns1/named.stats >ns1/named.stats.timeouts-before || true
mv ns1/named.stats ns1/named.stats-before
# 'resolver-query-timeout' is set to 5 seconds in ns1, so dig with a lower
# timeout value should give up earlier than that.
n=$((n + 1))
@@ -66,6 +72,20 @@ grep -F "EDE: 22 (No Reachable Authority)" dig.out.ns1.test${n} >/dev/null || re
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking that the timeout didn't skew the resolver responses counters and did update the timeout counter ($n)"
ret=0
rndccmd 10.53.0.1 stats || ret=1
grep -F 'responses received' ns1/named.stats >ns1/named.stats.responses-after || true
grep -F 'queries with RTT' ns1/named.stats >ns1/named.stats.rtt-after || true
grep -F 'query timeouts' ns1/named.stats >ns1/named.stats.timeouts-after || true
mv ns1/named.stats ns1/named.stats-after
diff ns1/named.stats.responses-before ns1/named.stats.responses-after >/dev/null || ret=1
diff ns1/named.stats.rtt-before ns1/named.stats.rtt-after >/dev/null || ret=1
diff ns1/named.stats.timeouts-before ns1/named.stats.timeouts-after >/dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
# 'resolver-query-timeout' is set to 5 seconds in ns1, so named should
# interrupt the non-responsive query and send a SERVFAIL answer before dig's
# own timeout fires, which is set to 7 seconds. This time, exampleudp.net is
@@ -729,10 +749,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 +1035,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
@@ -21,6 +21,7 @@ pytestmark = pytest.mark.extra_artifacts(
"nextpart.out.*",
"ans*/ans.run",
"ans*/query.log",
"ns1/named.stats*",
"ns4/tld.db",
"ns5/trusted.conf",
"ns6/K*",
-136
View File
@@ -1,136 +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.
*/
dnssec-policy "manual-rollover" {
dnskey-ttl 3600;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "multisigner-model2" {
dnskey-ttl 3600;
inline-signing no;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@ tag-range 32768 65535;
};
};
dnssec-policy "enable-dnssec" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 300;
max-zone-ttl PT12H;
zone-propagation-delay PT5M;
retire-safety PT20M;
publish-safety PT5M;
parent-propagation-delay 1h;
parent-ds-ttl 2h;
keys {
csk lifetime unlimited algorithm @DEFAULT_ALGORITHM_NUMBER@;
};
};
dnssec-policy "zsk-prepub" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 3600;
publish-safety P1D;
retire-safety P2D;
purge-keys PT1H;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime P30D algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay PT1H;
max-zone-ttl 1d;
};
dnssec-policy "ksk-doubleksk" {
signatures-refresh P1W;
signatures-validity P2W;
signatures-validity-dnskey P2W;
dnskey-ttl 2h;
publish-safety P1D;
retire-safety P2D;
purge-keys PT1H;
cdnskey no;
keys {
ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay PT1H;
max-zone-ttl 1d;
parent-ds-ttl 3600;
parent-propagation-delay PT1H;
};
dnssec-policy "csk-roll1" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
purge-keys PT1H;
cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes
keys {
csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay 1h;
max-zone-ttl P1D;
parent-ds-ttl 1h;
parent-propagation-delay 1h;
};
dnssec-policy "csk-roll2" {
signatures-refresh 12h;
signatures-validity P1D;
signatures-validity-dnskey P1D;
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 1h;
purge-keys 0;
cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes
keys {
csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@;
};
zone-propagation-delay PT1H;
max-zone-ttl 1d;
parent-ds-ttl PT1H;
parent-propagation-delay P1W;
};
-252
View File
@@ -1,252 +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.
*/
// NS3
include "kasp.conf";
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
dnssec-validation no;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../_common/root.hint.blackhole";
};
/* Manual rollover. */
zone "manual-rollover.kasp" {
type primary;
file "manual-rollover.kasp.db";
dnssec-policy "manual-rollover";
};
/* RFC 8901 Multi-signer Model 2. */
zone "multisigner-model2.kasp" {
type primary;
file "multisigner-model2.kasp.db";
dnssec-policy "multisigner-model2";
allow-update { any; };
};
/*
* A zone that starts with keys that have tags that are
* outside of the desired multi-signer key tag range.
*/
zone "single-to-multisigner.kasp" {
type primary;
file "single-to-multisigner.kasp.db";
dnssec-policy "multisigner-model2";
allow-update { any; };
};
/*
* Zones for testing enabling DNSSEC.
*/
zone "step1.enable-dnssec.autosign" {
type primary;
file "step1.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step2.enable-dnssec.autosign" {
type primary;
file "step2.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step3.enable-dnssec.autosign" {
type primary;
file "step3.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
zone "step4.enable-dnssec.autosign" {
type primary;
file "step4.enable-dnssec.autosign.db";
dnssec-policy "enable-dnssec";
};
/*
* Zones for testing ZSK Pre-Publication steps.
*/
zone "step1.zsk-prepub.autosign" {
type primary;
file "step1.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step2.zsk-prepub.autosign" {
type primary;
file "step2.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step3.zsk-prepub.autosign" {
type primary;
file "step3.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step4.zsk-prepub.autosign" {
type primary;
file "step4.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step5.zsk-prepub.autosign" {
type primary;
file "step5.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
zone "step6.zsk-prepub.autosign" {
type primary;
file "step6.zsk-prepub.autosign.db";
dnssec-policy "zsk-prepub";
};
/*
* Zones for testing KSK Double-KSK steps.
*/
zone "step1.ksk-doubleksk.autosign" {
type primary;
file "step1.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step2.ksk-doubleksk.autosign" {
type primary;
file "step2.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step3.ksk-doubleksk.autosign" {
type primary;
file "step3.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step4.ksk-doubleksk.autosign" {
type primary;
file "step4.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step5.ksk-doubleksk.autosign" {
type primary;
file "step5.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
zone "step6.ksk-doubleksk.autosign" {
type primary;
file "step6.ksk-doubleksk.autosign.db";
dnssec-policy "ksk-doubleksk";
};
/*
* Zone for testing GL #2375: Three is a crowd.
*/
zone "three-is-a-crowd.kasp" {
type primary;
file "three-is-a-crowd.kasp.db";
inline-signing yes;
/* Use same policy as KSK rollover test zones. */
dnssec-policy "ksk-doubleksk";
};
/*
* Zones for testing CSK rollover steps.
*/
zone "step1.csk-roll1.autosign" {
type primary;
file "step1.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step2.csk-roll1.autosign" {
type primary;
file "step2.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step3.csk-roll1.autosign" {
type primary;
file "step3.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step4.csk-roll1.autosign" {
type primary;
file "step4.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step5.csk-roll1.autosign" {
type primary;
file "step5.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step6.csk-roll1.autosign" {
type primary;
file "step6.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step7.csk-roll1.autosign" {
type primary;
file "step7.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step8.csk-roll1.autosign" {
type primary;
file "step8.csk-roll1.autosign.db";
dnssec-policy "csk-roll1";
};
zone "step1.csk-roll2.autosign" {
type primary;
file "step1.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step2.csk-roll2.autosign" {
type primary;
file "step2.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step3.csk-roll2.autosign" {
type primary;
file "step3.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step4.csk-roll2.autosign" {
type primary;
file "step4.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step5.csk-roll2.autosign" {
type primary;
file "step5.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step6.csk-roll2.autosign" {
type primary;
file "step6.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
zone "step7.csk-roll2.autosign" {
type primary;
file "step7.csk-roll2.autosign.db";
dnssec-policy "csk-roll2";
};
File diff suppressed because it is too large Load Diff
@@ -1,30 +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.
*/
dnssec-policy "csk-algoroll" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
@@ -1,76 +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.
*/
dnssec-policy "unlimited-lifetime" {
keys {
csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "short-lifetime" {
keys {
csk lifetime P6M algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "long-lifetime" {
keys {
csk lifetime P1Y algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "unsigning" {
dnskey-ttl 7200;
keys {
ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@;
zsk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@;
};
};
dnssec-policy "rsasha256" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
ksk lifetime unlimited algorithm rsasha256;
zsk lifetime unlimited algorithm rsasha256;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
dnssec-policy "ecdsa256" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
ksk lifetime unlimited algorithm ecdsa256;
zsk lifetime unlimited algorithm ecdsa256;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
@@ -1,33 +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.
*/
include "kasp-fips.conf";
dnssec-policy "rsasha1" {
signatures-refresh P5D;
signatures-validity 30d;
signatures-validity-dnskey 30d;
keys {
ksk lifetime unlimited algorithm rsasha1;
zsk lifetime unlimited algorithm rsasha1;
};
dnskey-ttl 1h;
publish-safety PT1H;
retire-safety 2h;
zone-propagation-delay 3600;
max-zone-ttl 6h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
-120
View File
@@ -1,120 +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.
*/
// NS6
include "kasp.conf";
include "csk1.conf";
options {
query-source address 10.53.0.6;
notify-source 10.53.0.6;
transfer-source 10.53.0.6;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.6; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
key-directory ".";
dnssec-validation no;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../_common/root.hint.blackhole";
};
/* This zone switch from dynamic to inline-signing. */
zone "dynamic2inline.kasp" {
type primary;
file "dynamic2inline.kasp.db";
allow-update { any; };
dnssec-policy "default";
};
/* Lifetime changes. */
zone longer-lifetime {
type primary;
file "longer-lifetime.db";
dnssec-policy short-lifetime;
};
zone shorter-lifetime {
type primary;
file "shorter-lifetime.db";
dnssec-policy long-lifetime;
};
zone limit-lifetime {
type primary;
file "limit-lifetime.db";
dnssec-policy unlimited-lifetime;
};
zone unlimit-lifetime {
type primary;
file "unlimit-lifetime.db";
dnssec-policy short-lifetime;
};
/* These zones are going insecure. */
zone "step1.going-insecure.kasp" {
type primary;
file "step1.going-insecure.kasp.db";
dnssec-policy "unsigning";
};
zone "step1.going-insecure-dynamic.kasp" {
type primary;
file "step1.going-insecure-dynamic.kasp.db";
dnssec-policy "unsigning";
inline-signing no;
allow-update { any; };
};
zone "step1.going-straight-to-none.kasp" {
type primary;
file "step1.going-straight-to-none.kasp.db";
dnssec-policy "default";
};
zone "step1.going-straight-to-none-dynamic.kasp" {
type primary;
file "step1.going-straight-to-none-dynamic.kasp.db.signed";
inline-signing no;
dnssec-policy "default";
allow-update { any; };
};
/* These are alorithm rollover test zones. */
zone "step1.algorithm-roll.kasp" {
type primary;
file "step1.algorithm-roll.kasp.db";
dnssec-policy "rsasha256";
};
zone "step1.csk-algorithm-roll.kasp" {
type primary;
file "step1.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
@@ -1,198 +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.
*/
// NS6
include "kasp.conf";
include "csk2.conf";
options {
query-source address 10.53.0.6;
notify-source 10.53.0.6;
transfer-source 10.53.0.6;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.6; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
dnssec-validation no;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../_common/root.hint.blackhole";
};
/* This zone switch from dynamic to inline-signing. */
zone "dynamic2inline.kasp" {
type primary;
file "dynamic2inline.kasp.db";
allow-update { any; };
dnssec-policy "default";
};
/* Lifetime changes. */
zone longer-lifetime {
type primary;
file "longer-lifetime.db";
dnssec-policy long-lifetime;
};
zone shorter-lifetime {
type primary;
file "shorter-lifetime.db";
dnssec-policy short-lifetime;
};
zone limit-lifetime {
type primary;
file "limit-lifetime.db";
dnssec-policy short-lifetime;
};
zone unlimit-lifetime {
type primary;
file "unlimit-lifetime.db";
dnssec-policy unlimited-lifetime;
};
/* Zones for testing going insecure. */
zone "step1.going-insecure.kasp" {
type primary;
file "step1.going-insecure.kasp.db";
dnssec-policy "insecure";
};
zone "step2.going-insecure.kasp" {
type primary;
file "step2.going-insecure.kasp.db";
dnssec-policy "insecure";
};
zone "step1.going-insecure-dynamic.kasp" {
type primary;
file "step1.going-insecure-dynamic.kasp.db";
inline-signing no;
dnssec-policy "insecure";
allow-update { any; };
};
zone "step2.going-insecure-dynamic.kasp" {
type primary;
file "step2.going-insecure-dynamic.kasp.db";
inline-signing no;
dnssec-policy "insecure";
allow-update { any; };
};
zone "step1.going-straight-to-none.kasp" {
type primary;
file "step1.going-straight-to-none.kasp.db";
dnssec-policy "none";
};
zone "step1.going-straight-to-none-dynamic.kasp" {
type primary;
file "step1.going-straight-to-none-dynamic.kasp.db.signed";
inline-signing no;
dnssec-policy "none";
allow-update { any; };
};
/*
* Zones for testing KSK/ZSK algorithm roll.
*/
zone "step1.algorithm-roll.kasp" {
type primary;
file "step1.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step2.algorithm-roll.kasp" {
type primary;
file "step2.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step3.algorithm-roll.kasp" {
type primary;
file "step3.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step4.algorithm-roll.kasp" {
type primary;
file "step4.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step5.algorithm-roll.kasp" {
type primary;
file "step5.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
zone "step6.algorithm-roll.kasp" {
type primary;
file "step6.algorithm-roll.kasp.db";
dnssec-policy "ecdsa256";
};
/*
* Zones for testing CSK algorithm roll.
*/
zone "step1.csk-algorithm-roll.kasp" {
type primary;
file "step1.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step2.csk-algorithm-roll.kasp" {
type primary;
file "step2.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step3.csk-algorithm-roll.kasp" {
type primary;
file "step3.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step4.csk-algorithm-roll.kasp" {
type primary;
file "step4.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step5.csk-algorithm-roll.kasp" {
type primary;
file "step5.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
zone "step6.csk-algorithm-roll.kasp" {
type primary;
file "step6.csk-algorithm-roll.kasp.db";
dnssec-policy "csk-algoroll";
};
-390
View File
@@ -1,390 +0,0 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns6/setup.sh"
setup() {
zone="$1"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
}
# Make lines shorter by storing key states in environment variables.
H="HIDDEN"
R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
for zn in dynamic2inline.kasp shorter-lifetime longer-lifetime limit-lifetime \
unlimit-lifetime; do
setup $zn
cp template.db.in $zonefile
done
# The child zones (step1, step2) beneath these zones represent the various
# steps of unsigning a zone.
for zn in going-insecure.kasp going-insecure-dynamic.kasp; do
# Step 1:
# Set up a zone with dnssec-policy that is going insecure.
setup step1.$zn
echo "$zone" >>zones
T="now-10d"
S="now-12955mi"
keytimes="-P $T -A $T"
cdstimes="-P sync $S"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $cdstimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2)
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# Set up a zone with dnssec-policy that is going insecure. Don't add
# this zone to the zones file, because this zone is no longer expected
# to be fully signed.
setup step2.$zn
# The DS was withdrawn from the parent zone 26 hours ago.
D="now-26h"
keytimes="-P $T -A $T -I $D -D now"
cdstimes="-P sync $S -D sync $D"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $cdstimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $T -r $O $T -d $U $D -D ds $D "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK}.state"
echo "Lifetime: 5184000" >>"${ZSK}.state"
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
done
# These zones are going straight to "none" policy. This is undefined behavior.
T="now-10d"
S="now-12955mi"
csktimes="-P $T -A $T -P sync $S"
setup step1.going-straight-to-none.kasp
echo "$zone" >>zones
CSK=$($KEYGEN -k default $csktimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $O $TactN -z $O $TactN -r $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -z -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
setup step1.going-straight-to-none-dynamic.kasp
echo "$zone" >>zones
CSK=$($KEYGEN -k default $csktimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $O $TactN -z $O $TactN -r $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" >"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -z -x -s now-1h -e now+2w -o $zone -O full -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
#
# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
# algorithm rollover.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.algorithm-roll.kasp
echo "$zone" >>zones
TactN="now-7d"
TsbmN="now-161h"
ksktimes="-P ${TactN} -A ${TactN}"
zsktimes="-P ${TactN} -A ${TactN}"
KSK=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksktimes $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a RSASHA256 -L 3600 $zsktimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile"
private_type_record $zone 8 "$KSK" >>"$infile"
private_type_record $zone 8 "$ZSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# After the publication interval has passed the DNSKEY is OMNIPRESENT.
setup step2.algorithm-roll.kasp
# The time passed since the new algorithm keys have been introduced is 3 hours.
TpubN1="now-3h"
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h
TsbmN1="now+4h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# 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.
TpubN1="now-7h"
TsbmN1="now"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 4:
# The DS is swapped and can become OMNIPRESENT.
setup step4.algorithm-roll.kasp
# The time passed since the DS has been swapped is 3 hours.
TpubN1="now-10h"
TsbmN1="now-3h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -D ds $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TsbmN1 -P ds $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 5:
# 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.
TpubN1="now-12h"
TsbmN1="now-5h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $U $TsbmN1 -r $U $TsbmN1 -d $H $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $U $TsbmN1 -z $U $TsbmN1 "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 6:
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.algorithm-roll.kasp
# Additional time passed: 7h.
TpubN1="now-19h"
TsbmN1="now-12h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
zsk2times="-P ${TpubN1} -A ${TpubN1}"
KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1)
ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2)
KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3)
ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4)
$SETTIME -s -g $H -k $H $TsbmN1 -r $U $TsbmN1 -d $H $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $H -k $H $TsbmN1 -z $U $TsbmN1 "$ZSK1" >settime.out.$zone.2 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${KSK1}.state"
echo "Lifetime: 0" >>"${ZSK1}.state"
cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile"
private_type_record $zone 8 "$KSK1" >>"$infile"
private_type_record $zone 8 "$ZSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
#
# The zones at csk-algorithm-roll.kasp represent the various steps of a CSK
# algorithm rollover.
#
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.csk-algorithm-roll.kasp
echo "$zone" >>zones
TactN="now-7d"
TsbmN="now-161h"
csktimes="-P ${TactN} -A ${TactN}"
CSK=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1
cat template.db.in "${CSK}.key" >"$infile"
private_type_record $zone 5 "$CSK" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 2:
# After the publication interval has passed the DNSKEY is OMNIPRESENT.
setup step2.csk-algorithm-roll.kasp
# The time passed since the new algorithm keys have been introduced is 3 hours.
TpubN1="now-3h"
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h
TsbmN1="now+4h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I now"
newtimes="-P ${TpubN1} -A ${TpubN1}"
CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# 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.
TpubN1="now-7h"
TsbmN1="now"
ckstimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 4:
# The DS is swapped and can become OMNIPRESENT.
setup step4.csk-algorithm-roll.kasp
# The time passed since the DS has been swapped is 3 hours.
TpubN1="now-10h"
TsbmN1="now-3h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TsbmN1 -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $O $TsbmN1 -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 5:
# 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.
TpubN1="now-12h"
TsbmN1="now-5h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $U $TactN -r $U $TactN -z $U $TsbmN1 -d $H $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $O $TsbmN1 -d $O $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
# Step 6:
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.csk-algorithm-roll.kasp
# Additional time passed: 7h.
TpubN1="now-19h"
TsbmN1="now-12h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}"
newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2)
$SETTIME -s -g $H -k $H $TactN -r $U $TactN -z $U $TactN -d $H $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1
# Fake lifetime of old algorithm keys.
echo "Lifetime: 0" >>"${CSK1}.state"
cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile"
private_type_record $zone 5 "$CSK1" >>"$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile"
cp $infile $zonefile
$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1
-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
-39
View File
@@ -1,39 +0,0 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../conf.sh
set -e
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns3/kasp.conf.in ns3/kasp.conf
copy_setports ns6/named.conf.in ns6/named.conf
copy_setports ns6/named2.conf.in ns6/named2.conf
copy_setports ns6/csk1.conf.in ns6/csk1.conf
copy_setports ns6/csk2.conf.in ns6/csk2.conf
copy_setports ns6/kasp-fips.conf.in ns6/kasp-fips.conf
copy_setports ns6/kasp.conf.in ns6/kasp.conf
if [ $RSASHA1_SUPPORTED = 0 ]; then
cp ns6/kasp-fips.conf ns6/kasp.conf
fi
(
cd ns3
$SHELL setup.sh
)
(
cd ns6
$SHELL setup.sh
)
File diff suppressed because it is too large Load Diff
+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*",
+3 -2
View File
@@ -264,7 +264,8 @@ sub construct_ns_command {
foreach my $t_option(
"dropedns", "ednsformerr", "ednsnotimp", "ednsrefused",
"noaa", "noedns", "nosoa", "maxudp512", "maxudp1460",
"cookiealwaysvalid", "noaa", "noedns", "nosoa",
"maxudp512", "maxudp1460",
) {
if (-e "$testdir/$server/named.$t_option") {
$command .= "-T $t_option "
@@ -323,7 +324,7 @@ sub construct_ans_command {
}
if (-e "$testdir/$server/ans.py") {
$ENV{'PYTHONPATH'} = $testdir . ":" . $ENV{'srcdir'};
$ENV{'PYTHONPATH'} = $testdir . ":" . $builddir;
$command = "$PYTHON -u ans.py 10.53.0.$n $queryport";
} elsif (-e "$testdir/$server/ans.pl") {
$command = "$PERL ans.pl";
+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))

Some files were not shown because too many files have changed in this diff Show More