Compare commits
71
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c7397b9cb | ||
|
|
a5ae37ad0b | ||
|
|
e081ab6ecf | ||
|
|
9604b13d00 | ||
|
|
d7a667d91b | ||
|
|
70470169a9 | ||
|
|
9bb834750d | ||
|
|
d17eda82e0 | ||
|
|
ca3e61a462 | ||
|
|
7f07c989b5 | ||
|
|
83115b931d | ||
|
|
184c7caff9 | ||
|
|
4199d2d5e4 | ||
|
|
6a5e60231f | ||
|
|
49ecb158d4 | ||
|
|
8e7229f641 | ||
|
|
3415392d01 | ||
|
|
2e6107008d | ||
|
|
341b962665 | ||
|
|
d3db9ccf53 | ||
|
|
e1e10adc3a | ||
|
|
d2214cb704 | ||
|
|
3e836a87e6 | ||
|
|
b93cb2e80e | ||
|
|
6c6b8796d3 | ||
|
|
8c9d2eb2bf | ||
|
|
63edc4435f | ||
|
|
ef671919d5 | ||
|
|
329a332708 | ||
|
|
bfbaacc9a0 | ||
|
|
8dba96d71e | ||
|
|
1d688e89b8 | ||
|
|
c2e60f9a5a | ||
|
|
ed727ee924 | ||
|
|
00584d6f29 | ||
|
|
d30b9eb46e | ||
|
|
0c7fa8d572 | ||
|
|
830e548111 | ||
|
|
12e7dfa397 | ||
|
|
c6e5710846 | ||
|
|
575a874582 | ||
|
|
68fe9a5df5 | ||
|
|
8c3f673f37 | ||
|
|
748ed4259b | ||
|
|
a956947fba | ||
|
|
e4c3186a7c | ||
|
|
5764a9d660 | ||
|
|
a2042e603e | ||
|
|
5eab352478 | ||
|
|
7f8226a039 | ||
|
|
192627db10 | ||
|
|
dfd37918d6 | ||
|
|
f413ddbe5f | ||
|
|
a799dd04ad | ||
|
|
7faa34c6ee | ||
|
|
575a2e5f11 | ||
|
|
0d9f58b745 | ||
|
|
05d6542e6d | ||
|
|
ff73d37f69 | ||
|
|
9d9e9d9cb1 | ||
|
|
1ab889ee21 | ||
|
|
ae2fd7ef15 | ||
|
|
4e75a20b6a | ||
|
|
807ef8545d | ||
|
|
06427720f7 | ||
|
|
d0a59277fb | ||
|
|
21ca763bca | ||
|
|
474b7a04f1 | ||
|
|
5dfcedd52d | ||
|
|
7c308c2298 | ||
|
|
f0b5f0cbce |
+6
-6
@@ -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
|
||||
|
||||
+17
-3
@@ -328,6 +328,7 @@ help(void) {
|
||||
" +[no]yaml (Present the results as "
|
||||
"YAML)\n"
|
||||
" +[no]zflag (Set Z flag in query)\n"
|
||||
" +[no]zoneversion (Request zone version)\n"
|
||||
" global d-opts and servers (before host name) affect "
|
||||
"all "
|
||||
"queries.\n"
|
||||
@@ -2574,9 +2575,22 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
|
||||
lookup->rrcomments = -1;
|
||||
}
|
||||
break;
|
||||
case 'z': /* zflag */
|
||||
FULLCHECK("zflag");
|
||||
lookup->zflag = state;
|
||||
case 'z':
|
||||
switch (cmd[1]) {
|
||||
case 'f': /* zflag */
|
||||
FULLCHECK("zflag");
|
||||
lookup->zflag = state;
|
||||
break;
|
||||
case 'o': /* zoneversion */
|
||||
FULLCHECK("zoneversion");
|
||||
if (state && lookup->edns == -1) {
|
||||
lookup->edns = DEFAULT_EDNS_VERSION;
|
||||
}
|
||||
lookup->zoneversion = state;
|
||||
break;
|
||||
default:
|
||||
goto invalid_option;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
invalid_option:
|
||||
|
||||
@@ -757,6 +757,10 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
|
||||
This option sets [or does not set] the last unassigned DNS header flag in a DNS query.
|
||||
This flag is off by default.
|
||||
|
||||
.. option:: +zoneversion, +nozoneversion
|
||||
|
||||
When enabled, this option includes an EDNS Zone Version request when sending a query.
|
||||
|
||||
Multiple Queries
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -705,6 +705,7 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
|
||||
looknew->opcode = lookold->opcode;
|
||||
looknew->expire = lookold->expire;
|
||||
looknew->nsid = lookold->nsid;
|
||||
looknew->zoneversion = lookold->zoneversion;
|
||||
looknew->tcp_keepalive = lookold->tcp_keepalive;
|
||||
looknew->header_only = lookold->header_only;
|
||||
looknew->https_mode = lookold->https_mode;
|
||||
@@ -2591,6 +2592,14 @@ setup_lookup(dig_lookup_t *lookup) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (lookup->zoneversion) {
|
||||
INSIST(i < MAXOPTS);
|
||||
opts[i].code = DNS_OPT_ZONEVERSION;
|
||||
opts[i].length = 0;
|
||||
opts[i].value = NULL;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (lookup->ednsoptscnt != 0) {
|
||||
INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
|
||||
memmove(&opts[i], lookup->ednsopts,
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ struct dig_lookup {
|
||||
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;
|
||||
ttlunits, use_usec, waiting_connect, zflag, zoneversion;
|
||||
char textname[MXNAME]; /*% Name we're going to be looking up */
|
||||
char cmdline[MXNAME];
|
||||
dns_rdatatype_t rdtype;
|
||||
|
||||
@@ -99,6 +99,7 @@ options {\n\
|
||||
recursing-file \"named.recursing\";\n\
|
||||
recursive-clients 1000;\n\
|
||||
request-nsid false;\n\
|
||||
request-zoneversion false;\n\
|
||||
resolver-query-timeout 10;\n\
|
||||
# responselog <boolean>;\n\
|
||||
rrset-order { order random; };\n\
|
||||
@@ -239,6 +240,7 @@ options {\n\
|
||||
notify yes;\n\
|
||||
notify-delay 5;\n\
|
||||
notify-to-soa no;\n\
|
||||
provide-zoneversion yes;\n\
|
||||
send-report-channel .;\n\
|
||||
serial-update-method increment;\n\
|
||||
sig-signing-nodes 100;\n\
|
||||
@@ -260,6 +262,7 @@ view \"_bind\" chaos {\n\
|
||||
notify no;\n\
|
||||
allow-new-zones no;\n\
|
||||
max-cache-size 2M;\n\
|
||||
provide-zoneversion no;\n\
|
||||
\n\
|
||||
# Prevent use of this zone in DNS amplified reflection DoS attacks\n\
|
||||
rate-limit {\n\
|
||||
|
||||
+7
-1
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1391,6 +1391,13 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
|
||||
CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
(void)cfg_map_get(cpeer, "request-zoneversion", &obj);
|
||||
if (obj != NULL) {
|
||||
CHECK(dns_peer_setrequestzoneversion(peer,
|
||||
cfg_obj_asboolean(obj)));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
(void)cfg_map_get(cpeer, "send-cookie", &obj);
|
||||
if (obj != NULL) {
|
||||
@@ -3246,6 +3253,7 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
|
||||
|
||||
dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
|
||||
dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
|
||||
dns_zone_setoption(zone, DNS_ZONEOPT_ZONEVERSION, false);
|
||||
dns_zone_setcheckdstype(zone, dns_checkdstype_no);
|
||||
dns_zone_setnotifytype(zone, dns_notifytype_no);
|
||||
dns_zone_setautomatic(zone, true);
|
||||
@@ -5132,6 +5140,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->requestnsid = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "request-zoneversion", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->requestzoneversion = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "send-cookie", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
||||
@@ -358,6 +358,8 @@ init_desc(void) {
|
||||
SET_NSSTATDESC(expireopt, "Expire option received", "ExpireOpt");
|
||||
SET_NSSTATDESC(keepaliveopt, "EDNS TCP keepalive option received",
|
||||
"KeepAliveOpt");
|
||||
SET_NSSTATDESC(zoneversionopt, "ZONEVERSION option received",
|
||||
"ZoneVersionOpt");
|
||||
SET_NSSTATDESC(padopt, "EDNS padding option received", "PadOpt");
|
||||
SET_NSSTATDESC(otheropt, "Other EDNS option received", "OtherOpt");
|
||||
SET_NSSTATDESC(cookiein, "COOKIE option received", "CookieIn");
|
||||
@@ -1603,7 +1605,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 +2662,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));
|
||||
|
||||
+12
-8
@@ -1227,6 +1227,12 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
||||
dns_zone_setkasp(zone, NULL);
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "provide-zoneversion", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS && obj != NULL);
|
||||
dns_zone_setoption(zone, DNS_ZONEOPT_ZONEVERSION,
|
||||
cfg_obj_asboolean(obj));
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "notify", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS && obj != NULL);
|
||||
@@ -1279,22 +1285,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 +1944,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);
|
||||
|
||||
@@ -31,6 +31,7 @@ server 0.0.0.0 {
|
||||
request-ixfr no;
|
||||
request-ixfr-max-diffs 0;
|
||||
request-nsid no;
|
||||
request-zoneversion no;
|
||||
require-cookie no;
|
||||
send-cookie no;
|
||||
tcp-keepalive no;
|
||||
@@ -55,6 +56,7 @@ server :: {
|
||||
request-ixfr no;
|
||||
request-ixfr-max-diffs 0;
|
||||
request-nsid no;
|
||||
request-zoneversion no;
|
||||
require-cookie no;
|
||||
send-cookie no;
|
||||
tcp-keepalive no;
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,6 +19,7 @@ pytestmark = pytest.mark.extra_artifacts(
|
||||
"ans*/ans.run",
|
||||
"ans*/query.log",
|
||||
"ns1/named_dump.db*",
|
||||
"ns4/named.cookiealwaysvalid",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -36,4 +36,5 @@ zone "example" {
|
||||
zone "example.tld" {
|
||||
type primary;
|
||||
file "example.tld.db";
|
||||
provide-zoneversion no;
|
||||
};
|
||||
|
||||
@@ -801,6 +801,73 @@ if [ -x "$DIG" ]; then
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +zoneversion to a authoritative server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +zoneversion a.example >dig.out.test$n 2>&1 || ret=1
|
||||
pat="; ZONEVERSION: ZONE: example, SOA-SERIAL: 2000042407"
|
||||
grep "$pat" 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 "checking dig +zoneversion to a authoritative server with zoneversion disabled ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +zoneversion a.example.tld >dig.out.test$n 2>&1 || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
grep "; ZONEVERSION:" dig.out.test$n >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if [ $HAS_PYYAML -ne 0 ]; then
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +yaml +zoneversion to a authoritative server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +yaml +zoneversion a.example >dig.out.test$n 2>&1 || ret=1
|
||||
$PYTHON yamlget.py dig.out.test$n 0 message response_message_data OPT_PSEUDOSECTION EDNS ZONEVERSION >yamlget.out.test$n 2>&1 || ret=1
|
||||
read -r value <yamlget.out.test$n
|
||||
expected="{'ZONE': 'example', 'SOA-SERIAL': 2000042407}"
|
||||
[ "$value" = "$expected" ] || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
fi
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +ednsopt=ZONEVERSION:<answer> to a authoritative server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +ednsopt=ZONEVERSION:0100000007DA a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1
|
||||
grep "; ZONEVERSION:" 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 "checking dig +zoneversion to a recursive server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.3 +zoneversion a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep '; ZONEVERSION:' 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 "checking display of non serial type zoneversion ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +qr +ednsopt=ZONEVERSION:0100000007DA a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep '; ZONEVERSION: LABELS: 1, TYPE: 0, VALUE: 000007da ("....")' dig.out.test$n >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if [ $HAS_PYYAML -ne 0 ]; then
|
||||
n=$((n + 1))
|
||||
echo_i "checking display of non serial type zoneversion +yaml ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +qr +ednsopt=ZONEVERSION:0100000007DA a.example +yaml >dig.out.test$n 2>&1 || ret=1
|
||||
$PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS ZONEVERSION >yamlget.out.test$n 2>&1 || ret=1
|
||||
expected="{'ZONE': 'example', 'TYPE': 1, 'VALUE': 000007da, PVALUE: '....'}"
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
fi
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig gracefully handles bad escape in domain name ($n)"
|
||||
ret=0
|
||||
|
||||
@@ -2191,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\|NSEC\)') || 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -130,7 +130,7 @@ $KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone >keygen.out.$zone.2 2>&1
|
||||
zone="multisigner-model2.kasp"
|
||||
echo_i "setting up zone: $zone"
|
||||
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.1)
|
||||
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zone -M 32768:65535 2>keygen.out.$zone.2)
|
||||
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.2)
|
||||
cat "${KSK}.key" | grep -v ";.*" >>"${zone}.db"
|
||||
cat "${ZSK}.key" | grep -v ";.*" >>"${zone}.db"
|
||||
# Import the ZSK sets of the other providers into their DNSKEY RRset.
|
||||
@@ -350,10 +350,9 @@ setup step2.enable-dnssec.autosign
|
||||
TpubN="now-900s"
|
||||
# RRSIG TTL: 12 hour (43200 seconds)
|
||||
# zone-propagation-delay: 5 minutes (300 seconds)
|
||||
# retire-safety: 20 minutes (1200 seconds)
|
||||
# Already passed time: -900 seconds
|
||||
# Total: 43800 seconds
|
||||
TsbmN="now+43800s"
|
||||
# Total: 42600 seconds
|
||||
TsbmN="now+42600s"
|
||||
keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
|
||||
CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2>keygen.out.$zone.1)
|
||||
$SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1
|
||||
@@ -365,10 +364,10 @@ $SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $i
|
||||
# Step 3:
|
||||
# The zone signatures have been published long enough to become OMNIPRESENT.
|
||||
setup step3.enable-dnssec.autosign
|
||||
# Passed time since publications: 43800 + 900 = 44700 seconds.
|
||||
TpubN="now-44700s"
|
||||
# Passed time since publications: 42600 + 900 = 43500 seconds.
|
||||
TpubN="now-43500s"
|
||||
# The key is secure for using in chain of trust when the DNSKEY is OMNIPRESENT.
|
||||
TcotN="now-43800s"
|
||||
TcotN="now-42600s"
|
||||
# We can submit the DS now.
|
||||
TsbmN="now"
|
||||
keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
|
||||
|
||||
@@ -127,9 +127,9 @@ setup step2.algorithm-roll.kasp
|
||||
# The time passed since the new algorithm keys have been introduced is 3 hours.
|
||||
TactN="now-3h"
|
||||
TpubN1="now-3h"
|
||||
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp + publish-safety =
|
||||
# now - 3h + 6h + 1h + 1h = now + 5h
|
||||
TsbmN1="now+5h"
|
||||
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp =
|
||||
# now - 3h + 6h + 1h = now + 4h
|
||||
TsbmN1="now+4h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I now"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -156,11 +156,11 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# Step 3:
|
||||
# The zone signatures are also OMNIPRESENT.
|
||||
setup step3.algorithm-roll.kasp
|
||||
# The time passed since the new algorithm keys have been introduced is 9 hours.
|
||||
TactN="now-9h"
|
||||
TretN="now-6h"
|
||||
TpubN1="now-9h"
|
||||
TsbmN1="now-1h"
|
||||
# The time passed since the new algorithm keys have been introduced is 7 hours.
|
||||
TactN="now-7h"
|
||||
TretN="now-3h"
|
||||
TpubN1="now-7h"
|
||||
TsbmN1="now"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -188,11 +188,11 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# The DS is swapped and can become OMNIPRESENT.
|
||||
setup step4.algorithm-roll.kasp
|
||||
# The time passed since the DS has been swapped is 29 hours.
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TpubN1="now-38h"
|
||||
TsbmN1="now-30h"
|
||||
TactN1="now-29h"
|
||||
TactN="now-36h"
|
||||
TretN="now-33h"
|
||||
TpubN1="now-36h"
|
||||
TsbmN1="now-29h"
|
||||
TactN1="now-27h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -220,12 +220,12 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# The DNSKEY is removed long enough to be HIDDEN.
|
||||
setup step5.algorithm-roll.kasp
|
||||
# The time passed since the DNSKEY has been removed is 2 hours.
|
||||
TactN="now-40h"
|
||||
TretN="now-37h"
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TremN="now-2h"
|
||||
TpubN1="now-40h"
|
||||
TsbmN1="now-32h"
|
||||
TactN1="now-31h"
|
||||
TpubN1="now-38h"
|
||||
TsbmN1="now-31h"
|
||||
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}"
|
||||
@@ -253,13 +253,13 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
|
||||
# The RRSIGs have been removed long enough to be HIDDEN.
|
||||
setup step6.algorithm-roll.kasp
|
||||
# Additional time passed: 7h.
|
||||
TactN="now-47h"
|
||||
TretN="now-44h"
|
||||
TactN="now-45h"
|
||||
TretN="now-42h"
|
||||
TremN="now-7h"
|
||||
TpubN1="now-47h"
|
||||
TsbmN1="now-39h"
|
||||
TactN1="now-38h"
|
||||
TdeaN="now-9h"
|
||||
TpubN1="now-45h"
|
||||
TsbmN1="now-38h"
|
||||
TactN1="now-36h"
|
||||
TdeaN="now-7h"
|
||||
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
|
||||
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
|
||||
@@ -324,11 +324,11 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# Step 3:
|
||||
# The zone signatures are also OMNIPRESENT.
|
||||
setup step3.csk-algorithm-roll.kasp
|
||||
# The time passed since the new algorithm keys have been introduced is 9 hours.
|
||||
TactN="now-9h"
|
||||
TretN="now-6h"
|
||||
TpubN1="now-9h"
|
||||
TactN1="now-6h"
|
||||
# The time passed since the new algorithm keys have been introduced is 7 hours.
|
||||
TactN="now-7h"
|
||||
TretN="now-3h"
|
||||
TpubN1="now-7h"
|
||||
TactN1="now-3h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
|
||||
@@ -347,10 +347,10 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# The DS is swapped and can become OMNIPRESENT.
|
||||
setup step4.csk-algorithm-roll.kasp
|
||||
# The time passed since the DS has been swapped is 29 hours.
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TpubN1="now-38h"
|
||||
TactN1="now-35h"
|
||||
TactN="now-36h"
|
||||
TretN="now-33h"
|
||||
TpubN1="now-36h"
|
||||
TactN1="now-33h"
|
||||
TsubN1="now-29h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
@@ -370,11 +370,11 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# The DNSKEY is removed long enough to be HIDDEN.
|
||||
setup step5.csk-algorithm-roll.kasp
|
||||
# The time passed since the DNSKEY has been removed is 2 hours.
|
||||
TactN="now-40h"
|
||||
TretN="now-37h"
|
||||
TactN="now-38h"
|
||||
TretN="now-35h"
|
||||
TremN="now-2h"
|
||||
TpubN1="now-40h"
|
||||
TactN1="now-37h"
|
||||
TpubN1="now-38h"
|
||||
TactN1="now-35h"
|
||||
TsubN1="now-31h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
@@ -394,12 +394,12 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
|
||||
# The RRSIGs have been removed long enough to be HIDDEN.
|
||||
setup step6.csk-algorithm-roll.kasp
|
||||
# Additional time passed: 7h.
|
||||
TactN="now-47h"
|
||||
TretN="now-44h"
|
||||
TactN="now-45h"
|
||||
TretN="now-42h"
|
||||
TdeaN="now-9h"
|
||||
TremN="now-7h"
|
||||
TpubN1="now-47h"
|
||||
TactN1="now-44h"
|
||||
TpubN1="now-45h"
|
||||
TactN1="now-42h"
|
||||
TsubN1="now-38h"
|
||||
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
|
||||
newtimes="-P ${TpubN1} -A ${TpubN1}"
|
||||
|
||||
+120
-125
@@ -275,9 +275,8 @@ set_keytimes_csk_policy() {
|
||||
set_keytime "KEY1" "ACTIVE" "${created}"
|
||||
# The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
|
||||
# publish-safety (1h) plus zone-propagation-delay (300s) =
|
||||
# 86400 + 3600 + 300 = 90300.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 90300
|
||||
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 86700
|
||||
# Key lifetime is unlimited, so not setting RETIRED and REMOVED.
|
||||
}
|
||||
|
||||
@@ -769,9 +768,8 @@ set_keytimes_algorithm_policy() {
|
||||
|
||||
# The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
|
||||
# publish-safety (1h) plus zone-propagation-delay (300s) =
|
||||
# 86400 + 3600 + 300 = 90300.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
|
||||
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
|
||||
# Key lifetime is 10 years, 315360000 seconds.
|
||||
set_addkeytime "KEY1" "RETIRED" "${published}" 315360000
|
||||
# The key is removed after the retire time plus DS TTL (1d),
|
||||
@@ -1720,10 +1718,10 @@ published=$(awk '{print $3}' <published.test${n}.key1)
|
||||
set_keytime "KEY1" "PUBLISHED" "${published}"
|
||||
set_keytime "KEY1" "ACTIVE" "${published}"
|
||||
published=$(key_get KEY1 PUBLISHED)
|
||||
# The DS can be published if the DNSKEY and RRSIG records are OMNIPRESENT.
|
||||
# This happens after max-zone-ttl (1d) plus publish-safety (1h) plus
|
||||
# zone-propagation-delay (300s) = 86400 + 3600 + 300 = 90300.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
|
||||
# The DS can be published if the zone is fully signed.
|
||||
# This happens after max-zone-ttl (1d) plus
|
||||
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
|
||||
# Key lifetime is 6 months, 315360000 seconds.
|
||||
set_addkeytime "KEY1" "RETIRED" "${published}" 16070400
|
||||
# The key is removed after the retire time plus DS TTL (1d), parent
|
||||
@@ -2486,9 +2484,9 @@ set_keytime "KEY1" "PUBLISHED" "${created}"
|
||||
set_keytime "KEY1" "ACTIVE" "${created}"
|
||||
# - The DS can be published if the DNSKEY and RRSIG records are
|
||||
# OMNIPRESENT. This happens after max-zone-ttl (12h) plus
|
||||
# publish-safety (5m) plus zone-propagation-delay (5m) =
|
||||
# 43200 + 300 + 300 = 43800.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
|
||||
# plus zone-propagation-delay (5m) =
|
||||
# 43200 + 300 = 43500.
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43500
|
||||
# - Key lifetime is unlimited, so not setting RETIRED and REMOVED.
|
||||
|
||||
# Various signing policy checks.
|
||||
@@ -2556,7 +2554,7 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "PUBLISHED" "${created}" -900
|
||||
set_addkeytime "KEY1" "ACTIVE" "${created}" -900
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
|
||||
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 42600
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -2566,8 +2564,8 @@ dnssec_verify
|
||||
|
||||
# Next key event is when the zone signatures become OMNIPRESENT: max-zone-ttl
|
||||
# plus zone propagation delay plus retire safety minus the already elapsed
|
||||
# 900 seconds: 12h + 300s + 20m - 900 = 44700 - 900 = 43800 seconds
|
||||
check_next_key_event 43800
|
||||
# 900 seconds: 12h + 300s + 20m - 900 = 43500 - 900 = 42600 seconds
|
||||
check_next_key_event 42600
|
||||
|
||||
#
|
||||
# Zone: step3.enable-dnssec.autosign.
|
||||
@@ -2584,10 +2582,10 @@ check_keys
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The key was published and activated 44700 seconds ago (with settime).
|
||||
# - The key was published and activated 43500 seconds ago (with settime).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "PUBLISHED" "${created}" -44700
|
||||
set_addkeytime "KEY1" "ACTIVE" "${created}" -44700
|
||||
set_addkeytime "KEY1" "PUBLISHED" "${created}" -43500
|
||||
set_addkeytime "KEY1" "ACTIVE" "${created}" -43500
|
||||
set_keytime "KEY1" "SYNCPUBLISH" "${created}"
|
||||
|
||||
# Continue signing policy checks.
|
||||
@@ -2603,8 +2601,8 @@ check_cdslog "$DIR" "$ZONE" KEY1
|
||||
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "published" "$ZONE"
|
||||
# Next key event is when the DS can move to the OMNIPRESENT state. This occurs
|
||||
# when the parent propagation delay have passed, plus the DS TTL and retire
|
||||
# safety delay: 1h + 2h + 20m = 3h20m = 12000 seconds
|
||||
check_next_key_event 12000
|
||||
# safety delay: 1h + 2h = 3h = 10800 seconds
|
||||
check_next_key_event 10800
|
||||
|
||||
#
|
||||
# Zone: step4.enable-dnssec.autosign.
|
||||
@@ -4388,9 +4386,9 @@ check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when the DS becomes HIDDEN. This happens after the
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 1h + 1d = 26h = 93600 seconds.
|
||||
check_next_key_event 93600
|
||||
# parent propagation delay, and DS TTL:
|
||||
# 1h + 1d = 25h = 90000 seconds.
|
||||
check_next_key_event 90000
|
||||
|
||||
#
|
||||
# Zone: step2.going-insecure.kasp
|
||||
@@ -4456,8 +4454,8 @@ dnssec_verify
|
||||
|
||||
# Next key event is when the DS becomes HIDDEN. This happens after the
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 1h + 1d = 26h = 93600 seconds.
|
||||
check_next_key_event 93600
|
||||
# 1h + 1d = 25h = 90000 seconds.
|
||||
check_next_key_event 90000
|
||||
|
||||
#
|
||||
# Zone: step2.going-insecure-dynamic.kasp
|
||||
@@ -4651,12 +4649,11 @@ set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_keytime "KEY3" "PUBLISHED" "${created}"
|
||||
set_keytime "KEY3" "ACTIVE" "${created}"
|
||||
# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
|
||||
# - It takes TTLsig + Dprp to propagate the zone.
|
||||
# TTLsig: 6h (39600 seconds)
|
||||
# Dprp: 1h (3600 seconds)
|
||||
# publish-safety: 1h (3600 seconds)
|
||||
# Ipub: 8h (28800 seconds)
|
||||
Ipub=28800
|
||||
# Ipub: 7h (25200 seconds)
|
||||
Ipub=25200
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${Ipub}"
|
||||
# - The new ZSK is published and activated.
|
||||
created=$(key_get KEY4 CREATED)
|
||||
@@ -4725,12 +4722,12 @@ dnssec_verify
|
||||
|
||||
# Next key event is when all zone signatures are signed with the new
|
||||
# algorithm. This is the max-zone-ttl plus zone propagation delay
|
||||
# plus retire safety: 6h + 1h + 2h. But three hours have already passed
|
||||
# (the time it took to make the DNSKEY omnipresent), so the next event
|
||||
# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
|
||||
# 6h + 1h. But three hours have already passed (the time it took to
|
||||
# make the DNSKEY omnipresent), so the next event should be scheduled
|
||||
# in 4 hour: 14400 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((21600 - time_passed))
|
||||
next_time=$((14400 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -4753,28 +4750,28 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
check_cdslog "$DIR" "$ZONE" KEY3
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 9 hours ago (32400 seconds).
|
||||
rollover_predecessor_keytimes -32400
|
||||
# - And retired 6 hours ago (21600 seconds).
|
||||
# - The old keys were activated 7 hours ago (25200 seconds).
|
||||
rollover_predecessor_keytimes -25200
|
||||
# - And retired 3 hours ago (10800 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -21600
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -10800
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -21600
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -10800
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
# - The new keys are published 9 hours ago.
|
||||
# - The new keys are published 7 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -32400
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -32400
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -25200
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -25200
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -32400
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -32400
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -25200
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -25200
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4787,9 +4784,9 @@ dnssec_verify
|
||||
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
|
||||
rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE"
|
||||
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 2h + 2h = 5h = 18000 seconds.
|
||||
check_next_key_event 18000
|
||||
# parent propagation delay, and DS TTL:
|
||||
# 1h + 2h = 3h = 10800 seconds.
|
||||
check_next_key_event 10800
|
||||
|
||||
#
|
||||
# Zone: step4.algorithm-roll.kasp
|
||||
@@ -4816,29 +4813,29 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 38 hours ago (136800 seconds).
|
||||
rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
# - The old keys were activated 36 hours ago (129600 seconds).
|
||||
rollover_predecessor_keytimes -129600
|
||||
# - And retired 33 hours ago (118800 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -118800
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -126000
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -118800
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
|
||||
# - The new keys are published 38 hours ago.
|
||||
# - The new keys are published 36 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -129600
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -129600
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -129600
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -129600
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4867,29 +4864,29 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 40 hours ago (144000 seconds)
|
||||
rollover_predecessor_keytimes -144000
|
||||
# - And retired 37 hours ago (133200 seconds).
|
||||
# - The old keys were activated 38 hours ago (136800 seconds)
|
||||
rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -133200
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -133200
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -126000
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
|
||||
# The new keys are published 40 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -144000
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -144000
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -144000
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -144000
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -4898,12 +4895,12 @@ check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
|
||||
# after the max-zone-ttl plus zone propagation delay plus retire safety
|
||||
# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
|
||||
# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
|
||||
# after the max-zone-ttl plus zone propagation delay (6h + 1h)
|
||||
# minus the time already passed since the UNRETENTIVE state has
|
||||
# been reached (2h): 7h - 2h = 5h = 18000 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((25200 - time_passed))
|
||||
next_time=$((18000 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -4921,29 +4918,29 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 47 hours ago (169200 seconds)
|
||||
rollover_predecessor_keytimes -169200
|
||||
# - And retired 44 hours ago (158400 seconds).
|
||||
# - The old keys were activated 45 hours ago (162000 seconds)
|
||||
rollover_predecessor_keytimes -162000
|
||||
# - And retired 42 hours ago (151200 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -158400
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -151200
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
|
||||
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -158400
|
||||
set_addkeytime "KEY2" "RETIRED" "${created}" -151200
|
||||
retired=$(key_get KEY2 RETIRED)
|
||||
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
|
||||
|
||||
# The new keys are published 47 hours ago.
|
||||
created=$(key_get KEY3 CREATED)
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -169200
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -169200
|
||||
set_addkeytime "KEY3" "PUBLISHED" "${created}" -162000
|
||||
set_addkeytime "KEY3" "ACTIVE" "${created}" -162000
|
||||
published=$(key_get KEY3 PUBLISHED)
|
||||
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
created=$(key_get KEY4 CREATED)
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -169200
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -169200
|
||||
set_addkeytime "KEY4" "PUBLISHED" "${created}" -162000
|
||||
set_addkeytime "KEY4" "ACTIVE" "${created}" -162000
|
||||
|
||||
# Continue signing policy checks.
|
||||
check_keytimes
|
||||
@@ -5026,9 +5023,8 @@ set_keytime "KEY2" "ACTIVE" "${created}"
|
||||
# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
|
||||
# TTLsig: 6h (39600 seconds)
|
||||
# Dprp: 1h (3600 seconds)
|
||||
# publish-safety: 1h (3600 seconds)
|
||||
# Ipub: 8h (28800 seconds)
|
||||
Ipub=28800
|
||||
# Ipub: 7h (25200 seconds)
|
||||
Ipub=25200
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}"
|
||||
|
||||
# Continue signing policy checks.
|
||||
@@ -5082,14 +5078,13 @@ check_apex
|
||||
check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when all zone signatures are signed with the new
|
||||
# algorithm. This is the max-zone-ttl plus zone propagation delay
|
||||
# plus retire safety: 6h + 1h + 2h. But three hours have already passed
|
||||
# (the time it took to make the DNSKEY omnipresent), so the next event
|
||||
# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((21600 - time_passed))
|
||||
# Next key event is when all zone signatures are signed with the new algorithm.
|
||||
# This is the max-zone-ttl plus zone propagation delay: 6h + 1h. But three
|
||||
# hours have already passed (the time it took to make the DNSKEY omnipresent),
|
||||
# so the next event should be scheduled in 4 hour: 14400 seconds. Prevent
|
||||
# intermittent false positives on slow platforms by subtracting the number of
|
||||
# seconds which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((14400 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -5114,17 +5109,17 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
check_cdslog "$DIR" "$ZONE" KEY2
|
||||
|
||||
# Set expected key times:
|
||||
# - The old key was activated 9 hours ago (32400 seconds).
|
||||
csk_rollover_predecessor_keytimes -32400
|
||||
# - And was retired 6 hours ago (21600 seconds).
|
||||
# - The old key was activated 7 hours ago (25200 seconds).
|
||||
csk_rollover_predecessor_keytimes -25200
|
||||
# - And was retired 3 hours ago (10800 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -21600
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -10800
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 9 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -32400
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -32400
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -25200
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -25200
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
|
||||
|
||||
@@ -5138,9 +5133,9 @@ dnssec_verify
|
||||
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
|
||||
rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE"
|
||||
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
|
||||
# parent propagation delay, retire safety delay, and DS TTL:
|
||||
# 1h + 2h + 2h = 5h = 18000 seconds.
|
||||
check_next_key_event 18000
|
||||
# parent propagation delay, and DS TTL:
|
||||
# 1h + 2h = 3h = 10800 seconds.
|
||||
check_next_key_event 10800
|
||||
|
||||
#
|
||||
# Zone: step4.csk-algorithm-roll.kasp
|
||||
@@ -5164,17 +5159,17 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old key was activated 38 hours ago (136800 seconds)
|
||||
csk_rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
# - The old keys were activated 36 hours ago (129600 seconds).
|
||||
csk_rollover_predecessor_keytimes -129600
|
||||
# - And retired 33 hours ago (118800 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -118800
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 38 hours ago.
|
||||
# - The new key was published 36 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -129600
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -129600
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
@@ -5204,17 +5199,17 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old key was activated 40 hours ago (144000 seconds)
|
||||
csk_rollover_predecessor_keytimes -144000
|
||||
# - And retired 37 hours ago (133200 seconds).
|
||||
# - The old key was activated 38 hours ago (136800 seconds)
|
||||
csk_rollover_predecessor_keytimes -136800
|
||||
# - And retired 35 hours ago (126000 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -133200
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 40 hours ago.
|
||||
# - The new key was published 38 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -144000
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -144000
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
@@ -5225,12 +5220,12 @@ check_subdomain
|
||||
dnssec_verify
|
||||
|
||||
# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
|
||||
# after the max-zone-ttl plus zone propagation delay plus retire safety
|
||||
# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
|
||||
# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
|
||||
# false positives on slow platforms by subtracting the number of seconds
|
||||
# which passed between key creation and invoking 'rndc reconfig'.
|
||||
next_time=$((25200 - time_passed))
|
||||
# after the max-zone-ttl plus zone propagation delay (6h + 1h) minus the
|
||||
# time already passed since the UNRETENTIVE state has been reached (2h):
|
||||
# 7h - 2h = 5h = 18000 seconds. Prevent intermittent false positives on slow
|
||||
# platforms by subtracting the number of seconds which passed between key
|
||||
# creation and invoking 'rndc reconfig'.
|
||||
next_time=$((18000 - time_passed))
|
||||
check_next_key_event $next_time
|
||||
|
||||
#
|
||||
@@ -5248,17 +5243,17 @@ wait_for_done_signing
|
||||
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
|
||||
|
||||
# Set expected key times:
|
||||
# - The old keys were activated 47 hours ago (169200 seconds)
|
||||
csk_rollover_predecessor_keytimes -169200
|
||||
# - And retired 44 hours ago (158400 seconds).
|
||||
# - The old keys were activated 45 hours ago (162000 seconds)
|
||||
csk_rollover_predecessor_keytimes -162000
|
||||
# - And retired 42 hours ago (151200 seconds).
|
||||
created=$(key_get KEY1 CREATED)
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -158400
|
||||
set_addkeytime "KEY1" "RETIRED" "${created}" -151200
|
||||
retired=$(key_get KEY1 RETIRED)
|
||||
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
|
||||
# - The new key was published 47 hours ago.
|
||||
created=$(key_get KEY2 CREATED)
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -169200
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -169200
|
||||
set_addkeytime "KEY2" "PUBLISHED" "${created}" -162000
|
||||
set_addkeytime "KEY2" "ACTIVE" "${created}" -162000
|
||||
published=$(key_get KEY2 PUBLISHED)
|
||||
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
; 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 ns2.good. hostmaster.arpa. 2018050100 1 1 1 1
|
||||
@ 30 NS ns2.good.
|
||||
|
||||
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.
|
||||
Executable → Regular
+91
-436
@@ -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
@@ -0,0 +1 @@
|
||||
good.db
|
||||
+1
@@ -0,0 +1 @@
|
||||
good.db
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@ 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
@@ -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.
|
||||
@@ -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
|
||||
Executable → Regular
+34
-273
@@ -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"
|
||||
@@ -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"
|
||||
Executable → Regular
+79
-331
@@ -1,345 +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.
|
||||
# This is only returned if a query for b.stale/NS has been made
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.a.b.stale."))
|
||||
r.additional.append(
|
||||
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
|
||||
)
|
||||
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.4")
|
||||
)
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -20,6 +20,8 @@ use IO::Socket;
|
||||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
print "Using Net::DNS $Net::DNS::VERSION\n";
|
||||
|
||||
my $localport = int($ENV{'PORT'});
|
||||
if (!$localport) { $localport = 5300; }
|
||||
|
||||
@@ -170,6 +172,15 @@ for (;;) {
|
||||
$packet->push("authority",
|
||||
new Net::DNS::RR($qname . " 300 SOA . . 0 0 0 0 0"));
|
||||
}
|
||||
} elsif ($qname eq "zoneversion") {
|
||||
$packet->push("authority", new Net::DNS::RR(". 300 SOA . . 0 0 0 0 0"));
|
||||
if ($Net::DNS::VERSION >= 1.49) {
|
||||
$packet->edns->option('ZONEVERSION' => [0, 1, '01022304'] )
|
||||
} elsif ($Net::DNS::VERSION >= 1.35) {
|
||||
$packet->edns->option('19' => {'BASE16' => '000101022304'} )
|
||||
} else {
|
||||
$packet->edns->option('19' => pack 'H*', '000101022304')
|
||||
}
|
||||
} else {
|
||||
# Data for the "bogus referrals" test
|
||||
$packet->push("authority", new Net::DNS::RR("below.www.example.com 300 NS ns.below.www.example.com"));
|
||||
|
||||
@@ -31,6 +31,7 @@ options {
|
||||
resolver-query-timeout 5000; # 5 seconds
|
||||
attach-cache "globalcache";
|
||||
max-recursion-queries 100;
|
||||
request-zoneversion yes;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
||||
@@ -26,6 +26,15 @@ options {
|
||||
querylog yes;
|
||||
prefetch 4 10;
|
||||
responselog yes;
|
||||
request-nsid yes;
|
||||
request-zoneversion yes;
|
||||
};
|
||||
|
||||
// Don't break tests which depend on ans10 by requesting
|
||||
// zoneversion or nsid
|
||||
server 10.53.0.10 {
|
||||
request-nsid no;
|
||||
request-zoneversion no;
|
||||
};
|
||||
|
||||
include "trusted.conf";
|
||||
|
||||
@@ -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
|
||||
@@ -881,6 +901,23 @@ test ${lines:-1} -ne 0 && ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that received ZONEVERSION is logged ($n)"
|
||||
ret=0
|
||||
pat="received ZONEVERSION serial 2010 from 10.53.0.4#[0-9]* for mixedttl.tld/TXT zone tld"
|
||||
grep "$pat" ns5/named.run >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that received ZONEVERSION is logged non serial ($n)"
|
||||
ret=0
|
||||
dig_with_opts +tcp @10.53.0.1 zoneversion >dig.out.${n} || ret=1
|
||||
pat='received ZONEVERSION type 1 value 01022304 (\.\.#\.) from 10.53.0.2#[0-9]* for zoneversion/A zone \.'
|
||||
grep "$pat" ns1/named.run >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check resolver behavior when FORMERR for EDNS options happens (${n})"
|
||||
ret=0
|
||||
|
||||
@@ -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*",
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -18,6 +18,7 @@ Changelog
|
||||
development. Regular users should refer to :ref:`Release Notes <relnotes>`
|
||||
for changes relevant to them.
|
||||
|
||||
.. include:: ../changelog/changelog-9.21.6.rst
|
||||
.. include:: ../changelog/changelog-9.21.5.rst
|
||||
.. include:: ../changelog/changelog-9.21.4.rst
|
||||
.. include:: ../changelog/changelog-9.21.3.rst
|
||||
|
||||
@@ -218,6 +218,7 @@ latex_logo = "isc-logo.pdf"
|
||||
linkcheck_timeout = 10
|
||||
linkcheck_ignore = [
|
||||
"http://127.0.0.1",
|
||||
"https://dl.acm.org",
|
||||
"https://gitlab.isc.org",
|
||||
"https://kb.isc.org",
|
||||
"https://simpleicon.com/",
|
||||
|
||||
@@ -127,3 +127,7 @@
|
||||
|
||||
``zoneload``
|
||||
Loading of zones and creation of automatic empty zones.
|
||||
|
||||
``zoneversion``
|
||||
ZONEVERSION options received from upstream servers.
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ The list of known issues affecting the latest version in the 9.21 branch can be
|
||||
found at
|
||||
https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.21
|
||||
|
||||
.. include:: ../notes/notes-9.21.6.rst
|
||||
.. include:: ../notes/notes-9.21.5.rst
|
||||
.. include:: ../notes/notes-9.21.4.rst
|
||||
.. include:: ../notes/notes-9.21.3.rst
|
||||
|
||||
@@ -2165,6 +2165,14 @@ Boolean Options
|
||||
ultimate primary should be set to still send NOTIFY messages to all the name servers
|
||||
listed in the NS RRset.
|
||||
|
||||
.. namedconf:statement:: provide-zoneversion
|
||||
:tags: transfer
|
||||
:short: Controls the return EDNS ZONEVERSION answers.
|
||||
|
||||
If ``yes`` EDNS ZONEVERSION answers will be returned otherwise
|
||||
not for primary, secondary and mirror zones. The default is
|
||||
``yes``.
|
||||
|
||||
.. namedconf:statement:: recursion
|
||||
:tags: query
|
||||
:short: Defines whether recursion and caching are allowed.
|
||||
@@ -2188,6 +2196,18 @@ Boolean Options
|
||||
option in its response, then its contents are logged in the ``nsid``
|
||||
category at level ``info``. The default is ``no``.
|
||||
|
||||
.. namedconf:statement:: request-zoneversion
|
||||
:tags: query
|
||||
:short: Controls whether an empty EDNS(0) ZONEVERSION option is sent with all queries to authoritative name servers during iterative resolution.
|
||||
|
||||
If ``yes``, then an empty EDNS(0) ZONEVERSION option is sent
|
||||
with all queries to authoritative name servers during iterative
|
||||
resolution. If the authoritative server returns an ZONEVERSION
|
||||
option in its response, then its contents are logged in the
|
||||
``zoneversion`` category at level ``info``. If the NSID has
|
||||
also been requested and it is returned then that is appended to
|
||||
the log message. The default is ``no``.
|
||||
|
||||
.. namedconf:statement:: require-cookie
|
||||
:tags: query
|
||||
:short: Controls whether responses without a server cookie are accepted.
|
||||
@@ -5601,11 +5621,13 @@ and :namedconf:ref:`options` blocks:
|
||||
- :namedconf:ref:`notify-source-v6`
|
||||
- :namedconf:ref:`notify-source`
|
||||
- :namedconf:ref:`provide-ixfr`
|
||||
- :namedconf:ref:`provide-zoneversion`
|
||||
- :namedconf:ref:`query-source-v6`
|
||||
- :namedconf:ref:`query-source`
|
||||
- :namedconf:ref:`request-expire`
|
||||
- :namedconf:ref:`request-ixfr`
|
||||
- :namedconf:ref:`request-nsid`
|
||||
- :namedconf:ref:`request-zoneversion`
|
||||
- :namedconf:ref:`require-cookie`
|
||||
- :namedconf:ref:`send-cookie`
|
||||
- :namedconf:ref:`transfer-format`
|
||||
|
||||
@@ -0,0 +1,478 @@
|
||||
.. 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.
|
||||
|
||||
BIND 9.21.6
|
||||
-----------
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Implement the min-transfer-rate-in configuration option.
|
||||
``a282f1ba3f``
|
||||
|
||||
A new option 'min-transfer-rate-in <bytes> <minutes>' has been added
|
||||
to the view and zone configurations. It can abort incoming zone
|
||||
transfers which run very slowly due to network related issues, for
|
||||
example. The default value is set to 10240 bytes in 5 minutes.
|
||||
:gl:`#3914` :gl:`!9098`
|
||||
|
||||
- Add digest methods for SIG and RRSIG. ``fd48df20f3``
|
||||
|
||||
ZONEMD digests RRSIG records and potentially digests SIG record. Add
|
||||
digests methods for both record types. :gl:`#5219` :gl:`!10217`
|
||||
|
||||
- Add HTTPS record query to host command line tool. ``d34414c47b``
|
||||
|
||||
The host command was extended to also query for the HTTPS RR type by
|
||||
default. :gl:`!8642`
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- Clean up unnecessary code in qpcache. ``74c9ff384e``
|
||||
|
||||
Removed some code from the cache database implementation that was left
|
||||
over from before it and the zone database implementation were
|
||||
separated. :gl:`!9991`
|
||||
|
||||
- Cleanup isc/util.h header and friends. ``239712df16``
|
||||
|
||||
Cleanup short list macros from <isc/util.h>, remove two unused
|
||||
headers, move locking macros to respective headers and use only the
|
||||
C11 static assertion. :gl:`!10196`
|
||||
|
||||
- Remove check for the mandatory IPv6 support. ``daa9c17905``
|
||||
|
||||
IPv6 Advanced Socket API (:rfc:`3542`) is a hard requirement, remove
|
||||
the autoconf check to speed up the ./configure run a little bit.
|
||||
:gl:`!10201`
|
||||
|
||||
- Remove log initialization checks from named. ``1b3e7f52ec``
|
||||
|
||||
Logging initialization check is now redundant as there is a default
|
||||
global log context created during libisc's constructor.
|
||||
|
||||
`isc_log` calls can safely be made at any time outside libisc's
|
||||
constructor. :gl:`!10186`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- Refactor and simplify isc_symtab. ``5559539eb0``
|
||||
|
||||
This commit does several changes to isc_symtab:
|
||||
|
||||
1. Rewrite the isc_symtab to internally use isc_hashmap instead of
|
||||
hand-stiched hashtable.
|
||||
|
||||
2. Create a new isc_symtab_define_and_return() api, which returns
|
||||
the already defined symvalue on ISC_R_EXISTS; this allows users of
|
||||
the API to skip the isc_symtab_lookup()+isc_symtab_define() calls
|
||||
and directly call isc_symtab_define_and_return().
|
||||
|
||||
3. Merge isccc_symtab into isc_symtab - the only missing function
|
||||
was isccc_symtab_foreach() that was merged into isc_symtab API.
|
||||
|
||||
4. Add full set of unit tests for the isc_symtab API. :gl:`#5103`
|
||||
:gl:`!9921`
|
||||
|
||||
- Drop malformed notify messages early instead of decompressing them.
|
||||
``7fce7707db``
|
||||
|
||||
The DNS header shows if a message has multiple questions or invalid
|
||||
NOTIFY sections. We can drop these messages early, right after parsing
|
||||
the question. This matches RFC 9619 for multi-question messages and
|
||||
Unbound's handling of NOTIFY. We still parse the question to include
|
||||
it in our FORMERR response.
|
||||
|
||||
Add drop_msg_early() function to check for these conditions: -
|
||||
Messages with more than one question, as required by RFC 9619 - NOTIFY
|
||||
query messages containing answer sections (like Unbound) - NOTIFY
|
||||
messages containing authority sections (like Unbound) :gl:`#5158`,
|
||||
#3656 :gl:`!10056`
|
||||
|
||||
- Cleanup parts of the isc_mem API. ``4ba1ccfa2e``
|
||||
|
||||
This MR changes custom attach/detach implementation with refcount
|
||||
macros, replaces isc_mem_destroy() with isc_mem_detach(), and does
|
||||
various small cleanups. :gl:`!9456`
|
||||
|
||||
- Move the library initialization and shutdown to executables.
|
||||
``6e0c1f151c``
|
||||
|
||||
Instead of relying on unreliable order of execution of the library
|
||||
constructors and destructors, move them to individual binaries. The
|
||||
advantage is that the execution time and order will remain constant
|
||||
and will not depend on the dynamic load dependency solver.
|
||||
:gl:`!10069`
|
||||
|
||||
- Reduce memory used to store DNS names. ``24db1b1a8a``
|
||||
|
||||
The memory used to internally store the DNS names has been reduced.
|
||||
:gl:`!10140`
|
||||
|
||||
- Unify fips handling to isc_crypto and make the toggle one way.
|
||||
``3de629d6b7``
|
||||
|
||||
Since algorithm fetching is handled purely in libisc, FIPS mode
|
||||
toggling can be purely done in within the library instead of provider
|
||||
fetching in the binary for OpenSSL >=3.0.
|
||||
|
||||
Disabling FIPS mode isn't a realistic requirement and isn't done
|
||||
anywhere in the codebase. Make the FIPS mode toggle enable-only to
|
||||
reflect the situation. :gl:`!9920`
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Prevent a reference leak when using plugins. ``5604d3a44e``
|
||||
|
||||
The `NS_QUERY_DONE_BEGIN` and `NS_QUERY_DONE_SEND` plugin hooks could
|
||||
cause a reference leak if they returned `NS_HOOK_RETURN` without
|
||||
cleaning up the query context properly. :gl:`#2094` :gl:`!9971`
|
||||
|
||||
- Fix isc_quota bug. ``742d379d88``
|
||||
|
||||
Running jobs which were entered into the isc_quota queue is the
|
||||
responsibility of the isc_quota_release() function, which, when
|
||||
releasing a previously acquired quota, checks whether the queue is
|
||||
empty, and if it's not, it runs a job from the queue without touching
|
||||
the 'quota->used' counter. This mechanism is susceptible to a possible
|
||||
hangup of a newly queued job in case when between the time a decision
|
||||
has been made to queue it (because used >= max) and the time it was
|
||||
actually queued, the last quota was released. Since there is no more
|
||||
quotas to be released (unless arriving in the future), the newly
|
||||
entered job will be stuck in the queue.
|
||||
|
||||
Fix the issue by adding checks in both isc_quota_release() and
|
||||
isc_quota_acquire_cb() to make sure that the described hangup does not
|
||||
happen. Also see code comments. :gl:`#4965` :gl:`!10082`
|
||||
|
||||
- Fix dual-stack-servers configuration option. ``6af708f3b0``
|
||||
|
||||
The dual-stack-servers configuration option was not working as
|
||||
expected; the specified servers were not being used when they should
|
||||
have been, leading to resolution failures. This has been fixed.
|
||||
:gl:`#5019` :gl:`!9708`
|
||||
|
||||
- Implement sig0key-checks-limit and sig0message-checks-limit.
|
||||
``d78ebff861``
|
||||
|
||||
Previously a hard-coded limitation of maximum two key or message
|
||||
verification checks were introduced when checking the message's SIG(0)
|
||||
signature. It was done in order to protect against possible DoS
|
||||
attacks. The logic behind choosing the number 2 was that more than a
|
||||
single key should only be required during key rotations, and in that
|
||||
case two keys are enough. But later it became apparent that there are
|
||||
other use cases too where even more keys are required, see issue
|
||||
number #5050 in GitLab.
|
||||
|
||||
This change introduces two new configuration options for the views,
|
||||
`sig0key-checks-limit` and `sig0message-checks-limit`, which define
|
||||
how many keys are allowed to be checked to find a matching key, and
|
||||
how many message verifications are allowed to take place once a
|
||||
matching key has been found. The latter protects against expensive
|
||||
cryptographic operations when there are keys with colliding tags and
|
||||
algorithm numbers, with default being 2, and the former protects
|
||||
against a bit less expensive key parsing operations and defaults to
|
||||
16. :gl:`#5050` :gl:`!9967`
|
||||
|
||||
- Fix the data race causing a permanent active client increase.
|
||||
``479c366c2b``
|
||||
|
||||
Previously, a data race could cause a newly created fetch context for
|
||||
a new client to be used before it had been fully initialized, which
|
||||
would cause the query to become stuck; queries for the same data would
|
||||
be either paused indefinitely or dropped because of the
|
||||
`clients-per-query` limit. This has been fixed. :gl:`#5053`
|
||||
:gl:`!10146`
|
||||
|
||||
- Fix deferred validation of unsigned DS and DNSKEY records.
|
||||
``ebf1606f38``
|
||||
|
||||
When processing a query with the "checking disabled" bit set (CD=1),
|
||||
`named` stores the unvalidated result in the cache, marked "pending".
|
||||
When the same query is sent with CD=0, the cached data is validated,
|
||||
and either accepted as an answer, or ejected from the cache as
|
||||
invalid. This deferred validation was not attempted for DS and DNSKEY
|
||||
records if they had no cached signatures, causing spurious validation
|
||||
failures. We now complete the deferred validation in this scenario.
|
||||
|
||||
Also, if deferred validation fails, we now re-query the data to find
|
||||
out whether the zone has been corrected since the invalid data was
|
||||
cached. :gl:`#5066` :gl:`!10104`
|
||||
|
||||
- When recording an rr trace, use libtool. ``6320586df0``
|
||||
|
||||
When a system test is run with the `USE_RR` environment variable set
|
||||
to 1, an `rr` trace is now correctly generated for each instance of
|
||||
`named`. :gl:`#5079` :gl:`!10197`
|
||||
|
||||
- Do not cache signatures for rejected data. ``fc3a4d6f89``
|
||||
|
||||
The cache has been updated so that if new data is rejected - for
|
||||
example, because there was already existing data at a higher trust
|
||||
level - then its covering RRSIG will also be rejected. :gl:`#5132`
|
||||
:gl:`!9999`
|
||||
|
||||
- Fix wrong logging severity in do_nsfetch() ``1f6a16e6d0``
|
||||
|
||||
ISC_LOG_WARNING was used while ISC_LOG_DEBUG(3) was implied.
|
||||
:gl:`#5145` :gl:`!10017`
|
||||
|
||||
- Fix RPZ race condition during a reconfiguration. ``5ba811bea2``
|
||||
|
||||
With RPZ in use, `named` could terminate unexpectedly because of a
|
||||
race condition when a reconfiguration command was received using
|
||||
`rndc`. This has been fixed. :gl:`#5146` :gl:`!10079`
|
||||
|
||||
- "CNAME and other data check" not applied to all types. ``b694acbe45``
|
||||
|
||||
An incorrect optimization caused "CNAME and other data" errors not to
|
||||
be detected if certain types were at the same node as a CNAME. This
|
||||
has been fixed. :gl:`#5150` :gl:`!10033`
|
||||
|
||||
- Use named Service Parameter Keys (SvcParamKeys) by default.
|
||||
``3f61a87be3``
|
||||
|
||||
When converting SVCB records to text representation `named` now uses
|
||||
named `SvcParamKeys` values unless backward-compatible mode is
|
||||
activated, in which case the values which were not defined initially
|
||||
in RFC9460 and were added later (see [1]) are converted to opaque
|
||||
"keyNNNN" syntax, like, for example, "key7" instead of "dohpath".
|
||||
|
||||
Also a new `+[no]svcparamkeycompat` option is implemented for `dig`,
|
||||
which enables the backward-compatible mode and uses the opaque syntax,
|
||||
if required for interoperability with other software or scripts. By
|
||||
default, the compatibility mode is disabled.
|
||||
|
||||
[1] https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
|
||||
:gl:`#5156` :gl:`!10085`
|
||||
|
||||
- Relax private DNSKEY and RRSIG constraints. ``1bc7016d7a``
|
||||
|
||||
DNSKEY, KEY, RRSIG and SIG constraints have been relaxed to allow
|
||||
empty key and signature material after the algorithm identifier for
|
||||
PRIVATEOID and PRIVATEDNS. It is arguable whether this falls within
|
||||
the expected use of these types as no key material is shared and the
|
||||
signatures are ineffective but these are private algorithms and they
|
||||
can be totally insecure. :gl:`#5167` :gl:`!10083`
|
||||
|
||||
- Delete dead nodes when committing a new version. ``67255da4b3``
|
||||
|
||||
In the qpzone implementation of `dns_db_closeversion()`, if there are
|
||||
changed nodes that have no remaining data, delete them. :gl:`#5169`
|
||||
:gl:`!10089`
|
||||
|
||||
- Revert "Delete dead nodes when committing a new version"
|
||||
``b652d5327c``
|
||||
|
||||
This reverts commit 67255da4b376f65138b299dcd5eb6a3b7f9735a9,
|
||||
reversing changes made to 74c9ff384e695d1b27fa365d1fee84576f869d4c.
|
||||
:gl:`#5169` :gl:`!10224`
|
||||
|
||||
- Fix dns_qp_insert() checks in qpzone. ``d6b63210a8``
|
||||
|
||||
Remove code in the QP zone database to handle failures of
|
||||
`dns_qp_insert()` which can't actually happen. :gl:`#5171`
|
||||
:gl:`!10088`
|
||||
|
||||
- Remove NSEC/DS/NSEC3 RRSIG check from dns_message_parse.
|
||||
``f0785fedf1``
|
||||
|
||||
Previously, when parsing responses, named incorrectly rejected
|
||||
responses without matching RRSIG records for NSEC/DS/NSEC3 records in
|
||||
the authority section. This rejection, if appropriate, should have
|
||||
been left for the validator to determine and has been fixed.
|
||||
:gl:`#5185` :gl:`!10125`
|
||||
|
||||
- Fix TTL issue with ANY queries processed through RPZ "passthru"
|
||||
``23c1fbc609``
|
||||
|
||||
Answers to an "ANY" query which were processed by the RPZ "passthru"
|
||||
policy had the response-policy's `max-policy-ttl` value unexpectedly
|
||||
applied. This has been fixed. :gl:`#5187` :gl:`!10176`
|
||||
|
||||
- Save time when creating a slab from another slab. ``cf981ab13b``
|
||||
|
||||
The `dns_rdataslab_fromrdataset()` function creates a slab from an
|
||||
rdataset. If the source rdataset already uses a slab, then no
|
||||
processing is necessary; we can just copy the existing slab to a new
|
||||
location. :gl:`#5188` :gl:`!10162`
|
||||
|
||||
- Dnssec-signzone needs to check for a NULL key when setting offline.
|
||||
``26f8ee7229``
|
||||
|
||||
dnssec-signzone could dereference a NULL key pointer when resigning a
|
||||
zone. This has been fixed. :gl:`#5192` :gl:`!10161`
|
||||
|
||||
- Acquire the database reference before possibly last node release.
|
||||
``c4868b5bd9``
|
||||
|
||||
Acquire the database reference in the detachnode() to prevent the last
|
||||
reference to be release while the NODE_LOCK being locked. The
|
||||
NODE_LOCK is locked/unlocked inside the RCU critical section, thus it
|
||||
is most probably this should not pose a problem as the database uses
|
||||
call_rcu memory reclamation, but this it is still safer to acquire the
|
||||
reference before releasing the node. :gl:`#5194` :gl:`!10155`
|
||||
|
||||
- Fix a logic error in cache_name() ``02ef8ff01c``
|
||||
|
||||
A change in 6aba56ae8 (checking whether a rejected RRset was identical
|
||||
to the data it would have replaced, so that we could still cache a
|
||||
signature) inadvertently introduced cases where processing of a
|
||||
response would continue when previously it would have been skipped.
|
||||
:gl:`#5197` :gl:`!10157`
|
||||
|
||||
- Fix a bug in the statistics channel when querying zone transfers
|
||||
information. ``e02d73e7e3``
|
||||
|
||||
When querying zone transfers information from the statistics channel
|
||||
there was a rare possibility that `named` could terminate unexpectedly
|
||||
if a zone transfer was in a state when transferring from all the
|
||||
available primary servers had failed earlier. This has been fixed.
|
||||
:gl:`#5198` :gl:`!10182`
|
||||
|
||||
- Fix assertion failure when dumping recursing clients. ``796b662b92``
|
||||
|
||||
Previously, if a new counter was added to the hashtable while dumping
|
||||
recursing clients via the `rndc recursing` command, and
|
||||
`fetches-per-zone` was enabled, an assertion failure could occur. This
|
||||
has been fixed. :gl:`#5200` :gl:`!10164`
|
||||
|
||||
- Validating ADB fetches could cause a crash in import_rdataset()
|
||||
``49ccbe857a``
|
||||
|
||||
Previously, in some cases, the resolver could return rdatasets of type
|
||||
CNAME or DNAME without the result code being set to `DNS_R_CNAME` or
|
||||
`DNS_R_DNAME`. This could trigger an assertion failure in the ADB. The
|
||||
resolver error has been fixed. :gl:`#5201` :gl:`!10172`
|
||||
|
||||
- Call isc__iterated_hash_initialize in isc__work_cb. ``f3458fdf43``
|
||||
|
||||
isc_iterated_hash didn't work in offloaded threads as the per thread
|
||||
initialisation has not been done. This has been fixed. :gl:`#5214`
|
||||
:gl:`!10206`
|
||||
|
||||
- Fix a bug in get_request_transport_type() ``db5166ab99``
|
||||
|
||||
When `dns_remote_done()` is true, calling `dns_remote_curraddr()`
|
||||
asserts. Add a `dns_remote_curraddr()` check before calling
|
||||
`dns_remote_curraddr()`. :gl:`#5215` :gl:`!10222`
|
||||
|
||||
- Clean up dns_rdataslab module. ``948f8d7a98``
|
||||
|
||||
Rdata slabs used in the QP databases are usually prepended with a slab
|
||||
header, but are sometimes "raw", containing only the rdata and no
|
||||
header. Previously, to allow for them to be used both ways, functions
|
||||
that operated on them took a `reservelen` argument, which would be set
|
||||
to either the header length or to zero, and skipped over that many
|
||||
bytes at the beginning of the buffer. Most such functions were never
|
||||
used on the raw form. To make the code clearer, each of these
|
||||
functions now operates on full slabs with headers, and an alternate
|
||||
"raw" version of the function has been added in cases where that was
|
||||
needed.
|
||||
|
||||
In addition, the `dns_rdataslab_merge()` and `_subtract()` functions
|
||||
have been rewritten for clarity and efficiency, and a minor bug has
|
||||
been fixed in `dns_rdataslab_equal()` and `_equalx()`, which could
|
||||
cause an incorrect result if both slabs being compared had zero
|
||||
length. :gl:`!10084`
|
||||
|
||||
- Dump the active resolver fetches from dns_resolver_dumpfetches()
|
||||
``5d0c347e75``
|
||||
|
||||
Previously, active resolver fetches were only dumped when the
|
||||
`fetches-per-zone` configuration option was enabled. Now, active
|
||||
resolver fetches are dumped along with the number of
|
||||
`clients-per-server` counters per resolver fetch. :gl:`!10107`
|
||||
|
||||
- Fix the foundname vs dcname madness in qpcache_findzonecut()
|
||||
``4e68dbf194``
|
||||
|
||||
The qpcache_findzonecut() accepts two "foundnames": 'foundname' and
|
||||
'dcname' could be NULL. Originally, when 'dcname' would be NULL, the
|
||||
'dcname' would be set to 'foundname' which basically means that we
|
||||
were copying the .ndata over itself for no apparent reason.
|
||||
:gl:`!10049`
|
||||
|
||||
- Post [CVE-2024-12705] Performance Drop Fixes, Part 2. ``c8104daf8d``
|
||||
|
||||
This merge request addresses several key performance bottlenecks in
|
||||
the DoH (DNS over HTTPS) implementation by introducing significant
|
||||
optimizations and improvements.
|
||||
|
||||
### Key Improvements
|
||||
|
||||
1. **Simplification and Optimisation of `http_do_bio()` Function**:
|
||||
- The code flow in the `http_do_bio()` function has been significantly
|
||||
simplified. 2. **Flushing HTTP Write Buffer on Outgoing DNS
|
||||
Messages**: - The buffer is flushed and a send operation is
|
||||
performed when there is an outgoing DNS message. 3. **Bumping Active
|
||||
Streams Processing Limit**: - The total number of active streams
|
||||
has been increased to 60% of the total streams limit.
|
||||
|
||||
These changes collectively enhance the performance and reliability of
|
||||
the DoH implementation, making it more efficient and robust for
|
||||
handling high-load scenarios, particularly noticeable in long runs (>=
|
||||
1h) of `stress:long:rpz:doh+udp:linux:*` tests. It improves perf. for
|
||||
tests for BIND 9.18, but it likely will have a positive but less
|
||||
pronounced effect on newer versions as well.
|
||||
|
||||
In essence, the merge request fixes three bottlenecks stacked upon
|
||||
each other.
|
||||
|
||||
*It is a logical continuation of the merge requests !10109.* !10109,
|
||||
unfortunately, did not completely [address the performance drop in
|
||||
9.18](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/221545)
|
||||
for longer runs of the stress test. This merge request [addresses
|
||||
that](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/223661).
|
||||
|
||||
**P.S.**
|
||||
|
||||
The origin of the fixes is, in fact, the branch in !10193. So this MR
|
||||
is a ... *forward port* of them. :gl:`!10192`
|
||||
|
||||
- Post [CVE-2024-12705] Performance Drop Fixes. ``3033d127d2``
|
||||
|
||||
This merge request fixes a [performance
|
||||
drop](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/216728)
|
||||
after merging the fixes for #4795, in particular in 9.18.
|
||||
|
||||
The MR [fixes the
|
||||
problem](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/219825)
|
||||
without affecting performance for the newer versions, in particular
|
||||
for [the development version](https://gitlab.isc.org/isc-projects/bind
|
||||
9/-/pipelines/220619). :gl:`!10109`
|
||||
|
||||
- Remove 'target' from dns_adb. ``764eb65cf6``
|
||||
|
||||
When a server name turns out to be a CNAME or DNAME, the ADB does not
|
||||
use it, but the `dns_adbname` structure still stored a copy of the
|
||||
target name. This is unnecessary and the code has been removed.
|
||||
:gl:`!10149`
|
||||
|
||||
- Simplify some dns_name API calls. ``e16560a650``
|
||||
|
||||
Several functions in the `dns_name` module have had parameters
|
||||
removed, that were rarely or never used: - `dns_name_fromtext()` and
|
||||
`dns_name_concatenate()` no longer take a target buffer. -
|
||||
`dns_name_towire()` no longer takes a compression offset pointer; this
|
||||
is now part of the compression context. - `dns_name_towire()` with a
|
||||
`NULL` compression context will copy name data directly into a buffer
|
||||
with no processing. :gl:`!10152`
|
||||
|
||||
- Sync the TSAN CC, CFLAGS and LDFLAGS in the respdiff:tsan job.
|
||||
``22b5442722``
|
||||
|
||||
:gl:`!10209`
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ zone <string> [ <class> ] {
|
||||
notify-source ( <ipv4_address> | * );
|
||||
notify-source-v6 ( <ipv6_address> | * );
|
||||
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
provide-zoneversion <boolean>;
|
||||
request-expire <boolean>;
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
|
||||
@@ -226,6 +226,7 @@ options {
|
||||
preferred-glue <string>;
|
||||
prefetch <integer> [ <integer> ];
|
||||
provide-ixfr <boolean>;
|
||||
provide-zoneversion <boolean>;
|
||||
qname-minimization ( strict | relaxed | disabled | off );
|
||||
query-source [ address ] ( <ipv4_address> | * | none );
|
||||
query-source-v6 [ address ] ( <ipv6_address> | * | none );
|
||||
@@ -254,6 +255,7 @@ options {
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-server-cookie <boolean>;
|
||||
resolver-query-timeout <integer>;
|
||||
resolver-use-dns64 <boolean>;
|
||||
@@ -343,6 +345,7 @@ server <netprefix> {
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-cookie <boolean>;
|
||||
send-cookie <boolean>;
|
||||
tcp-keepalive <boolean>;
|
||||
@@ -509,6 +512,7 @@ view <string> [ <class> ] {
|
||||
preferred-glue <string>;
|
||||
prefetch <integer> [ <integer> ];
|
||||
provide-ixfr <boolean>;
|
||||
provide-zoneversion <boolean>;
|
||||
qname-minimization ( strict | relaxed | disabled | off );
|
||||
query-source [ address ] ( <ipv4_address> | * | none );
|
||||
query-source-v6 [ address ] ( <ipv6_address> | * | none );
|
||||
@@ -534,6 +538,7 @@ view <string> [ <class> ] {
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-server-cookie <boolean>;
|
||||
resolver-query-timeout <integer>;
|
||||
resolver-use-dns64 <boolean>;
|
||||
@@ -561,6 +566,7 @@ view <string> [ <class> ] {
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-cookie <boolean>;
|
||||
send-cookie <boolean>;
|
||||
tcp-keepalive <boolean>;
|
||||
|
||||
@@ -51,6 +51,7 @@ zone <string> [ <class> ] {
|
||||
parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
parental-source ( <ipv4_address> | * );
|
||||
parental-source-v6 ( <ipv6_address> | * );
|
||||
provide-zoneversion <boolean>;
|
||||
send-report-channel <string>;
|
||||
serial-update-method ( date | increment | unixtime );
|
||||
sig-signing-nodes <integer>;
|
||||
|
||||
@@ -50,6 +50,7 @@ zone <string> [ <class> ] {
|
||||
parental-source ( <ipv4_address> | * );
|
||||
parental-source-v6 ( <ipv6_address> | * );
|
||||
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
provide-zoneversion <boolean>;
|
||||
request-expire <boolean>;
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
.. 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.
|
||||
|
||||
Notes for BIND 9.21.6
|
||||
---------------------
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Implement the :any:`min-transfer-rate-in` configuration option.
|
||||
|
||||
A new option :any:`min-transfer-rate-in` has been added
|
||||
to the view and zone configurations. It can abort incoming zone
|
||||
transfers that run very slowly due to network-related issues, for
|
||||
example. The default value is 10240 bytes in five minutes.
|
||||
:gl:`#3914`
|
||||
|
||||
- Add HTTPS record query to :iscman:`host` command line tool.
|
||||
|
||||
The :iscman:`host` command was extended to also query for the HTTPS RR
|
||||
type by default.
|
||||
|
||||
- Implement :any:`sig0key-checks-limit` and :any:`sig0message-checks-limit`.
|
||||
|
||||
Previously, a hard-coded limitation of a maximum of two key or message
|
||||
verification checks was introduced when checking a message's ``SIG(0)``
|
||||
signature, to protect against possible DoS
|
||||
attacks. Two as a maximum was chosen so that more than a
|
||||
single key should only be required during key rotations, and in that
|
||||
case two keys are enough. It later became apparent that there are
|
||||
other use cases where even more keys are required; see the related GitLab issue for examples.
|
||||
|
||||
This change introduces two new configuration options for the views:
|
||||
:any:`sig0key-checks-limit` and :any:`sig0message-checks-limit`. They define
|
||||
how many keys can be checked to find a matching key, and
|
||||
how many message verifications are allowed to take place once a
|
||||
matching key has been found. The former provides
|
||||
slightly less "expensive" key parsing operations and defaults to
|
||||
16. The latter protects against expensive
|
||||
cryptographic operations when there are keys with colliding tags and
|
||||
algorithm numbers; the default is 2. :gl:`#5050`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- Drop malformed notify messages early instead of decompressing them.
|
||||
|
||||
The DNS header shows whether a message has multiple questions or invalid
|
||||
NOTIFY sections. :iscman:`named` can now drop these messages early, right after parsing
|
||||
the question, to match :rfc:`9619` for multi-question messages and
|
||||
Unbound's handling of NOTIFY. Questions are still parsed to be included
|
||||
in BIND's FORMERR response.
|
||||
|
||||
Add ``drop_msg_early()`` function to check for these conditions:
|
||||
|
||||
- Messages with more than one question, as required by :rfc:`9619`
|
||||
- NOTIFY query messages containing answer sections (like Unbound)
|
||||
|
||||
:gl:`#5158`
|
||||
|
||||
- Reduce memory used to store DNS names.
|
||||
|
||||
The memory used to internally store the DNS names has been reduced
|
||||
by no longer caching certain fields from an internal data structure.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Fix :any:`dual-stack-servers` configuration option.
|
||||
|
||||
The :any:`dual-stack-servers` configuration option was not working as
|
||||
expected; the specified servers were not being used when they should
|
||||
have been, leading to resolution failures. This has been fixed.
|
||||
:gl:`#5019`
|
||||
|
||||
- Fix a data race causing a permanent active client increase.
|
||||
|
||||
Previously, a data race could cause a newly created fetch context for
|
||||
a new client to be used before it had been fully initialized, which
|
||||
would cause the query to become stuck; queries for the same data would
|
||||
be either paused indefinitely or dropped because of the
|
||||
:any:`clients-per-query` limit. This has been fixed. :gl:`#5053`
|
||||
|
||||
- Fix deferred validation of unsigned DS and DNSKEY records.
|
||||
|
||||
When processing a query with the "checking disabled" bit set (CD=1),
|
||||
:iscman:`named` stores the invalidated result in the cache, marked "pending".
|
||||
When the same query is sent with CD=0, the cached data is validated
|
||||
and either accepted as an answer, or ejected from the cache as
|
||||
invalid. This deferred validation was not attempted for DS and DNSKEY
|
||||
records if they had no cached signatures, causing spurious validation
|
||||
failures. The deferred validation is now completed in this scenario.
|
||||
|
||||
Also, if deferred validation fails, the data is now re-queried to find
|
||||
out whether the zone has been corrected since the invalid data was
|
||||
cached. :gl:`#5066`
|
||||
|
||||
- Fix RPZ race condition during a reconfiguration.
|
||||
|
||||
With RPZ in use, :iscman:`named` could terminate unexpectedly because of a
|
||||
race condition when a reconfiguration command was received using
|
||||
:iscman:`rndc`. This has been fixed. :gl:`#5146`
|
||||
|
||||
- "CNAME and other data check" not applied to all types.
|
||||
|
||||
An incorrect optimization caused "CNAME and other data" errors not to
|
||||
be detected if certain types were at the same node as a CNAME. This
|
||||
has been fixed. :gl:`#5150`
|
||||
|
||||
- Use named Service Parameter Keys (``SvcParamKeys``) by default.
|
||||
|
||||
When converting SVCB records to text representation, :iscman:`named` now uses
|
||||
named ``SvcParamKeys`` values unless backward-compatible mode is
|
||||
activated. In that case, values which were not defined initially
|
||||
in :rfc:`9460` and were added later (see [1]) are converted to opaque
|
||||
"keyNNNN" syntax, e.g. "key7" instead of "dohpath".
|
||||
|
||||
Also a new ``+[no]svcparamkeycompat`` option is implemented for :iscman:`dig`,
|
||||
which enables the backward-compatible mode and uses the opaque syntax,
|
||||
if required for interoperability with other software or scripts. By
|
||||
default, the compatibility mode is disabled.
|
||||
|
||||
[1] https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
|
||||
:gl:`#5156`
|
||||
|
||||
- Relax private DNSKEY and RRSIG constraints.
|
||||
|
||||
DNSKEY, KEY, RRSIG, and SIG constraints have been relaxed to allow
|
||||
empty key and signature material after the algorithm identifier for
|
||||
PRIVATEOID and PRIVATEDNS. It is arguable whether this falls within
|
||||
the expected use of these types, as no key material is shared and the
|
||||
signatures are ineffective, but these are private algorithms and they
|
||||
can be totally insecure. :gl:`#5167`
|
||||
|
||||
- Remove NSEC/DS/NSEC3 RRSIG check from ``dns_message_parse()``.
|
||||
|
||||
Previously, when parsing responses, :iscman:`named` incorrectly rejected
|
||||
responses without matching RRSIG records for NSEC/DS/NSEC3 records in
|
||||
the authority section. This rejection, if appropriate, should have
|
||||
been left for the validator to determine and has been fixed.
|
||||
:gl:`#5185`
|
||||
|
||||
- Fix TTL issue with ANY queries processed through RPZ "passthru".
|
||||
|
||||
Answers to an "ANY" query which were processed by the RPZ "passthru"
|
||||
policy had the response-policy's ``max-policy-ttl`` value unexpectedly
|
||||
applied. This has been fixed. :gl:`#5187`
|
||||
|
||||
- :iscman:`dnssec-signzone` needs to check for a NULL key when setting offline.
|
||||
|
||||
:iscman:`dnssec-signzone` could dereference a NULL key pointer when resigning
|
||||
a zone. This has been fixed. :gl:`#5192`
|
||||
|
||||
- Fix a bug in the statistics channel when querying zone transfer
|
||||
information.
|
||||
|
||||
When querying zone transfer information from the statistics channel,
|
||||
there was a rare possibility that :iscman:`named` could terminate unexpectedly
|
||||
if a zone transfer was in a state when transferring from all the
|
||||
available primary servers had failed earlier. This has been fixed.
|
||||
:gl:`#5198`
|
||||
|
||||
- Fix assertion failure when dumping recursing clients.
|
||||
|
||||
Previously, if a new counter was added to the hash table while dumping
|
||||
recursing clients via the :option:`rndc recursing` command, and
|
||||
:any:`fetches-per-zone` was enabled, an assertion failure could occur. This
|
||||
has been fixed. :gl:`#5200`
|
||||
|
||||
- Dump the active resolver fetches from ``dns_resolver_dumpfetches()``
|
||||
|
||||
Previously, active resolver fetches were only dumped when the
|
||||
:any:`fetches-per-zone` configuration option was enabled. Now, active
|
||||
resolver fetches are dumped along with the number of
|
||||
:any:`clients-per-query` counters per resolver fetch.
|
||||
|
||||
|
||||
@@ -136,7 +136,6 @@ libdns_la_HEADERS = \
|
||||
include/dns/view.h \
|
||||
include/dns/xfrin.h \
|
||||
include/dns/zone.h \
|
||||
include/dns/zonekey.h \
|
||||
include/dns/zoneverify.h \
|
||||
include/dns/zt.h
|
||||
|
||||
@@ -255,7 +254,6 @@ libdns_la_SOURCES = \
|
||||
zone.c \
|
||||
zone_p.h \
|
||||
zoneverify.c \
|
||||
zonekey.c \
|
||||
zt.c
|
||||
|
||||
if HAVE_GSSAPI
|
||||
|
||||
+5
-5
@@ -1076,11 +1076,11 @@ new_adbfetch(dns_adb_t *adb) {
|
||||
dns_adbfetch_t *fetch = NULL;
|
||||
|
||||
fetch = isc_mem_get(adb->hmctx, sizeof(*fetch));
|
||||
*fetch = (dns_adbfetch_t){ 0 };
|
||||
*fetch = (dns_adbfetch_t){
|
||||
.magic = DNS_ADBFETCH_MAGIC,
|
||||
};
|
||||
dns_rdataset_init(&fetch->rdataset);
|
||||
|
||||
fetch->magic = DNS_ADBFETCH_MAGIC;
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
@@ -2909,6 +2909,7 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, bool no_validation,
|
||||
* createfetch to find deepest cached name when we're providing
|
||||
* domain and nameservers.
|
||||
*/
|
||||
dns_adbname_ref(adbname);
|
||||
result = dns_resolver_createfetch(
|
||||
adb->res, adbname->name, type, name, nameservers, NULL, NULL, 0,
|
||||
options, depth, qc, gqc, isc_loop(), fetch_callback, adbname,
|
||||
@@ -2916,11 +2917,10 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, bool no_validation,
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
DP(ENTER_LEVEL, "fetch_name: createfetch failed with %s",
|
||||
isc_result_totext(result));
|
||||
dns_adbname_unref(adbname);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
dns_adbname_ref(adbname);
|
||||
|
||||
if (type == dns_rdatatype_a) {
|
||||
adbname->fetch_a = fetch;
|
||||
inc_resstats(adb, dns_resstatscounter_gluefetchv4);
|
||||
|
||||
@@ -1200,3 +1200,14 @@ dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
|
||||
(db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
|
||||
isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_db_getzoneversion(dns_db_t *db, isc_buffer_t *b) {
|
||||
REQUIRE(db != NULL);
|
||||
REQUIRE(b != NULL);
|
||||
|
||||
if (db->methods->getzoneversion != NULL) {
|
||||
return (db->methods->getzoneversion)(db, b);
|
||||
}
|
||||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -1101,6 +1101,41 @@ dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_dnssec_iszonekey(dns_rdata_dnskey_t *key) {
|
||||
return (key->flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
|
||||
(key->flags & DNS_KEYTYPE_NOAUTH) == 0 &&
|
||||
(key->protocol == DNS_KEYPROTO_DNSSEC ||
|
||||
key->protocol == DNS_KEYPROTO_ANY);
|
||||
}
|
||||
|
||||
bool
|
||||
dns_dnssec_haszonekey(dns_rdataset_t *keyset) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(keyset != NULL);
|
||||
|
||||
if (keyset->type != dns_rdatatype_dnskey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (result = dns_rdataset_first(keyset); result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(keyset))
|
||||
{
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_dnskey_t key;
|
||||
|
||||
dns_rdataset_current(keyset, &rdata);
|
||||
dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
|
||||
|
||||
if (dns_dnssec_iszonekey(&key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
|
||||
dns_dnsseckey_t **dkp) {
|
||||
|
||||
+8
-19
@@ -162,8 +162,7 @@ computeid(dst_key_t *key);
|
||||
static isc_result_t
|
||||
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
||||
unsigned int protocol, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp);
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
|
||||
|
||||
static isc_result_t
|
||||
algorithm_status(unsigned int alg);
|
||||
@@ -721,13 +720,6 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
|
||||
isc_result_t
|
||||
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
|
||||
return dst_key_fromdns_ex(name, rdclass, source, mctx, false, keyp);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp) {
|
||||
uint8_t alg, proto;
|
||||
uint32_t flags, extflags;
|
||||
dst_key_t *key = NULL;
|
||||
@@ -756,7 +748,7 @@ dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
}
|
||||
|
||||
result = frombuffer(name, alg, flags, proto, rdclass, source, mctx,
|
||||
no_rdata, &key);
|
||||
&key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
@@ -775,7 +767,7 @@ dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
||||
isc_result_t result;
|
||||
|
||||
result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx,
|
||||
false, &key);
|
||||
&key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
@@ -2267,8 +2259,7 @@ computeid(dst_key_t *key) {
|
||||
static isc_result_t
|
||||
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
||||
unsigned int protocol, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp) {
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
|
||||
dst_key_t *key;
|
||||
isc_result_t ret;
|
||||
|
||||
@@ -2290,12 +2281,10 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
||||
return DST_R_UNSUPPORTEDALG;
|
||||
}
|
||||
|
||||
if (!no_rdata) {
|
||||
ret = key->func->fromdns(key, source);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_free(&key);
|
||||
return ret;
|
||||
}
|
||||
ret = key->func->fromdns(key, source);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_free(&key);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,7 @@ typedef struct dns_dbmethods {
|
||||
dns_name_t *name);
|
||||
void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
|
||||
void (*setmaxtypepername)(dns_db_t *db, uint32_t value);
|
||||
isc_result_t (*getzoneversion)(dns_db_t *db, isc_buffer_t *b);
|
||||
} dns_dbmethods_t;
|
||||
|
||||
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
|
||||
@@ -1805,3 +1806,21 @@ dns_db_setmaxtypepername(dns_db_t *db, uint32_t value);
|
||||
* stored at a given node, then any subsequent attempt to add an rdataset
|
||||
* with a new RR type will return ISC_R_TOOMANYRECORDS.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_db_getzoneversion(dns_db_t *db, isc_buffer_t *b);
|
||||
/*%<
|
||||
* Provides a database specific EDNS ZONEVERSION option.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'db' is a valid database
|
||||
* \li 'b' is a valid buffer
|
||||
*
|
||||
* Returns:
|
||||
* \li ISC_R_SUCCESS when it has populated the buffer with the ZONEVERSION
|
||||
* response (maybe empty implying no ZONEVERSION to be returned).
|
||||
* \li ISC_R_NOSPACE if the buffer is too small.
|
||||
* \li ISC_R_NOTIMPLEMENTED if there is not a database specific
|
||||
* ZONEVERSION
|
||||
* \li ISC_R_FAILURE other failures
|
||||
*/
|
||||
|
||||
@@ -242,6 +242,24 @@ dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
|
||||
* rrset. dns_dnssec_signs() works on any rrset.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_dnssec_iszonekey(dns_rdata_dnskey_t *key);
|
||||
/*%<
|
||||
* Verify that 'key' is a DNSSEC key with the DNS_KEYOWNER_ZONE flag set.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'key' is not NULL.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_dnssec_haszonekey(dns_rdataset_t *keyset);
|
||||
/*%<
|
||||
* Verify that 'keyset' includes at least one zone key.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'keyset' is not NULL.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
|
||||
dns_dnsseckey_t **dkp);
|
||||
|
||||
@@ -102,7 +102,6 @@
|
||||
#define DNS_MESSAGEEXTFLAG_DO 0x8000U
|
||||
|
||||
/*%< EDNS0 extended OPT codes */
|
||||
|
||||
#define DNS_OPT_LLQ 1 /*%< LLQ opt code */
|
||||
#define DNS_OPT_UL 2 /*%< UL opt code */
|
||||
#define DNS_OPT_NSID 3 /*%< NSID opt code */
|
||||
@@ -129,7 +128,7 @@
|
||||
* options we know about. Extended DNS Errors may occur multiple times, see
|
||||
* DNS_EDE_MAX_ERRORS.
|
||||
*/
|
||||
#define DNS_EDNSOPTIONS 8 + DNS_EDE_MAX_ERRORS
|
||||
#define DNS_EDNSOPTIONS 9 + DNS_EDE_MAX_ERRORS
|
||||
|
||||
#define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD)
|
||||
#define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
|
||||
|
||||
@@ -115,6 +115,12 @@ dns_peer_setrequestnsid(dns_peer_t *peer, bool newval);
|
||||
isc_result_t
|
||||
dns_peer_getrequestnsid(dns_peer_t *peer, bool *retval);
|
||||
|
||||
isc_result_t
|
||||
dns_peer_setrequestzoneversion(dns_peer_t *peer, bool newval);
|
||||
|
||||
isc_result_t
|
||||
dns_peer_getrequestzoneversion(dns_peer_t *peer, bool *retval);
|
||||
|
||||
isc_result_t
|
||||
dns_peer_setsendcookie(dns_peer_t *peer, bool newval);
|
||||
|
||||
|
||||
@@ -105,31 +105,32 @@ typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t;
|
||||
* Options that modify how a 'fetch' is done.
|
||||
*/
|
||||
enum {
|
||||
DNS_FETCHOPT_TCP = 1 << 0, /*%< Use TCP. */
|
||||
DNS_FETCHOPT_UNSHARED = 1 << 1, /*%< See below. */
|
||||
DNS_FETCHOPT_RECURSIVE = 1 << 2, /*%< Set RD? */
|
||||
DNS_FETCHOPT_NOEDNS0 = 1 << 3, /*%< Do not use EDNS. */
|
||||
DNS_FETCHOPT_FORWARDONLY = 1 << 4, /*%< Only use forwarders. */
|
||||
DNS_FETCHOPT_NOVALIDATE = 1 << 5, /*%< Disable validation. */
|
||||
DNS_FETCHOPT_WANTNSID = 1 << 6, /*%< Request NSID */
|
||||
DNS_FETCHOPT_PREFETCH = 1 << 7, /*%< Do prefetch */
|
||||
DNS_FETCHOPT_NOCDFLAG = 1 << 8, /*%< Don't set CD flag. */
|
||||
DNS_FETCHOPT_NONTA = 1 << 9, /*%< Ignore NTA table. */
|
||||
DNS_FETCHOPT_NOCACHED = 1 << 10, /*%< Force cache update. */
|
||||
DNS_FETCHOPT_QMINIMIZE = 1 << 11, /*%< Use qname minimization. */
|
||||
DNS_FETCHOPT_NOFOLLOW = 1 << 12, /*%< Don't retrieve the NS RRset
|
||||
* from the child zone when a
|
||||
* delegation is returned in
|
||||
* response to a NS query. */
|
||||
DNS_FETCHOPT_QMIN_STRICT = 1 << 13, /*%< Do not work around servers
|
||||
* that return errors on
|
||||
* non-empty terminals. */
|
||||
DNS_FETCHOPT_QMIN_SKIP_IP6A = 1 << 14, /*%< Skip some labels when
|
||||
* doing qname minimization
|
||||
* on ip6.arpa. */
|
||||
DNS_FETCHOPT_NOFORWARD = 1 << 15, /*%< Do not use forwarders if
|
||||
* possible. */
|
||||
DNS_FETCHOPT_QMINFETCH = 1 << 16, /*%< Qmin fetch */
|
||||
DNS_FETCHOPT_TCP = 1 << 0, /*%< Use TCP. */
|
||||
DNS_FETCHOPT_UNSHARED = 1 << 1, /*%< See below. */
|
||||
DNS_FETCHOPT_RECURSIVE = 1 << 2, /*%< Set RD? */
|
||||
DNS_FETCHOPT_NOEDNS0 = 1 << 3, /*%< Do not use EDNS. */
|
||||
DNS_FETCHOPT_FORWARDONLY = 1 << 4, /*%< Only use forwarders. */
|
||||
DNS_FETCHOPT_NOVALIDATE = 1 << 5, /*%< Disable validation. */
|
||||
DNS_FETCHOPT_WANTNSID = 1 << 6, /*%< Request NSID */
|
||||
DNS_FETCHOPT_PREFETCH = 1 << 7, /*%< Do prefetch */
|
||||
DNS_FETCHOPT_NOCDFLAG = 1 << 8, /*%< Don't set CD flag. */
|
||||
DNS_FETCHOPT_NONTA = 1 << 9, /*%< Ignore NTA table. */
|
||||
DNS_FETCHOPT_NOCACHED = 1 << 10, /*%< Force cache update. */
|
||||
DNS_FETCHOPT_QMINIMIZE = 1 << 11, /*%< Use qname minimization. */
|
||||
DNS_FETCHOPT_NOFOLLOW = 1 << 12, /*%< Don't retrieve the NS RRset
|
||||
* from the child zone when a
|
||||
* delegation is returned in
|
||||
* response to a NS query. */
|
||||
DNS_FETCHOPT_QMIN_STRICT = 1 << 13, /*%< Do not work around servers
|
||||
* that return errors on
|
||||
* non-empty terminals. */
|
||||
DNS_FETCHOPT_QMIN_SKIP_IP6A = 1 << 14, /*%< Skip some labels when
|
||||
* doing qname minimization
|
||||
* on ip6.arpa. */
|
||||
DNS_FETCHOPT_NOFORWARD = 1 << 15, /*%< Do not use forwarders if
|
||||
* possible. */
|
||||
DNS_FETCHOPT_QMINFETCH = 1 << 16, /*%< Qmin fetch */
|
||||
DNS_FETCHOPT_WANTZONEVERSION = 1 << 17, /*%< Request ZONEVERSION */
|
||||
|
||||
/*% EDNS version bits: */
|
||||
DNS_FETCHOPT_EDNSVERSIONSET = 1 << 23,
|
||||
|
||||
@@ -151,8 +151,8 @@ struct dns_validator {
|
||||
uint8_t unsupported_digest;
|
||||
dns_rdata_t rdata;
|
||||
bool resume;
|
||||
uint32_t *nvalidations;
|
||||
uint32_t *nfails;
|
||||
isc_counter_t *nvalidations;
|
||||
isc_counter_t *nfails;
|
||||
isc_counter_t *qc;
|
||||
isc_counter_t *gqc;
|
||||
|
||||
@@ -172,7 +172,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
||||
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
|
||||
dns_message_t *message, unsigned int options,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *arg,
|
||||
uint32_t *nvalidations, uint32_t *nfails,
|
||||
isc_counter_t *nvalidations, isc_counter_t *nfails,
|
||||
isc_counter_t *qc, isc_counter_t *gqc,
|
||||
dns_edectx_t *edectx, dns_validator_t **validatorp);
|
||||
/*%<
|
||||
|
||||
@@ -145,6 +145,7 @@ struct dns_view {
|
||||
dns_rrl_t *rrl;
|
||||
bool provideixfr;
|
||||
bool requestnsid;
|
||||
bool requestzoneversion;
|
||||
bool sendcookie;
|
||||
dns_ttl_t maxcachettl;
|
||||
dns_ttl_t maxncachettl;
|
||||
|
||||
+49
-41
@@ -102,6 +102,7 @@ typedef enum {
|
||||
DNS_ZONEOPT_CHECKTTL = 1 << 28, /*%< check max-zone-ttl */
|
||||
DNS_ZONEOPT_AUTOEMPTY = 1 << 29, /*%< automatic empty zone */
|
||||
DNS_ZONEOPT_CHECKSVCB = 1 << 30, /*%< check SVBC records */
|
||||
DNS_ZONEOPT_ZONEVERSION = 1U << 31, /*%< enable zoneversion */
|
||||
DNS_ZONEOPT___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */
|
||||
} dns_zoneopt_t;
|
||||
|
||||
@@ -818,7 +819,7 @@ dns_zone_setmaxretrytime(dns_zone_t *zone, uint32_t val);
|
||||
* val > 0.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
|
||||
/*%<
|
||||
* Set the source address to be used in IPv4 zone transfers.
|
||||
@@ -826,22 +827,20 @@ dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'xfrsource' to contain the address.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getxfrsource4(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getxfrsource4(dns_zone_t *zone, isc_sockaddr_t *xfrsource);
|
||||
/*%<
|
||||
* Returns the source address set by a previous dns_zone_setxfrsource4
|
||||
* call, or the default of inaddr_any, port 0.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'xfrsource' to not be NULL
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
|
||||
/*%<
|
||||
* Set the source address to be used in IPv6 zone transfers.
|
||||
@@ -849,22 +848,20 @@ dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'xfrsource' to contain the address.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getxfrsource6(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getxfrsource6(dns_zone_t *zone, isc_sockaddr_t *xfrsource);
|
||||
/*%<
|
||||
* Returns the source address set by a previous dns_zone_setxfrsource6
|
||||
* call, or the default of in6addr_any, port 0.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'xfrsource' to not be NULL
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
|
||||
/*%<
|
||||
* Set the source address to be used with IPv4 parental DS queries.
|
||||
@@ -872,22 +869,20 @@ dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'parentalsrc' to contain the address.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getparentalsrc4(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getparentalsrc4(dns_zone_t *zone, isc_sockaddr_t *parentalsrc);
|
||||
/*%<
|
||||
* Returns the source address set by a previous dns_zone_setparentalsrc4
|
||||
* call, or the default of inaddr_any, port 0.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'parentalsrc' to be non NULL.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
|
||||
/*%<
|
||||
* Set the source address to be used with IPv6 parental DS queries.
|
||||
@@ -895,22 +890,20 @@ dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'parentalsrc' to contain the address.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getparentalsrc6(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getparentalsrc6(dns_zone_t *zone, isc_sockaddr_t *parentalsrc);
|
||||
/*%<
|
||||
* Returns the source address set by a previous dns_zone_setparentalsrc6
|
||||
* call, or the default of in6addr_any, port 0.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'parentalsrc' to be non NULL.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
|
||||
/*%<
|
||||
* Set the source address to be used with IPv4 NOTIFY messages.
|
||||
@@ -918,22 +911,20 @@ dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'notifysrc' to contain the address.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getnotifysrc4(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getnotifysrc4(dns_zone_t *zone, isc_sockaddr_t *notifysrc);
|
||||
/*%<
|
||||
* Returns the source address set by a previous dns_zone_setnotifysrc4
|
||||
* call, or the default of inaddr_any, port 0.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'notifysrc' to be non NULL.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
|
||||
/*%<
|
||||
* Set the source address to be used with IPv6 NOTIFY messages.
|
||||
@@ -941,19 +932,17 @@ dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'notifysrc' to contain the address.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS
|
||||
*/
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getnotifysrc6(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getnotifysrc6(dns_zone_t *zone, isc_sockaddr_t *notifysrc);
|
||||
/*%<
|
||||
* Returns the source address set by a previous dns_zone_setnotifysrc6
|
||||
* call, or the default of in6addr_any, port 0.
|
||||
*
|
||||
* Require:
|
||||
*\li 'zone' to be a valid zone.
|
||||
*\li 'notifysrc' to be non NULL.
|
||||
*/
|
||||
|
||||
void
|
||||
@@ -1528,8 +1517,8 @@ dns_zone_getsigresigninginterval(dns_zone_t *zone);
|
||||
* \li 'zone' to be a valid zone.
|
||||
*/
|
||||
|
||||
isc_sockaddr_t
|
||||
dns_zone_getsourceaddr(dns_zone_t *zone);
|
||||
void
|
||||
dns_zone_getsourceaddr(dns_zone_t *zone, isc_sockaddr_t *sourceaddr);
|
||||
/*%<
|
||||
* Get the zone's source address from which it has last contacted the current
|
||||
* primary server.
|
||||
@@ -1537,17 +1526,18 @@ dns_zone_getsourceaddr(dns_zone_t *zone);
|
||||
* Requires:
|
||||
* \li 'zone' to be a valid zone.
|
||||
* \li 'zone' has a non-empty primaries list.
|
||||
* \li 'sourceaddr' to be non-NULL.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *dest);
|
||||
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *primaryaddr);
|
||||
/*%<
|
||||
* Get the zone's current primary server into '*dest'.
|
||||
* Get the zone's current primary server into '*primaryaddr'.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'zone' to be a valid zone.
|
||||
* \li 'zone' has a non-empty primaries list.
|
||||
* \li 'dest' != NULL.
|
||||
* \li 'primaryaddr' to be non-NULL.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS if the current primary server was found
|
||||
@@ -2796,6 +2786,24 @@ dns_zone_getrad(dns_zone_t *zone, dns_name_t *name);
|
||||
* \li 'name' is a valid name with a buffer.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getzoneversion(dns_zone_t *zone, isc_buffer_t *b);
|
||||
/**<
|
||||
* Return the EDNS ZONEVERSION for this zone.
|
||||
*
|
||||
* Note: For type SERIAL a buffer of at least 6 octets is required.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'zone' to be a valid zone.
|
||||
* \li 'b' to be a valid buffer.
|
||||
*
|
||||
* Returns
|
||||
* \li ISC_R_SUCCESS if the zone is loaded and supports ZONEVERSION.
|
||||
* \li ISC_R_NOSPACE if the buffer is too small.
|
||||
* \li DNS_R_NOTLOADED if the database is not loaded.
|
||||
* \li ISC_R_FAILURE other failure.
|
||||
*/
|
||||
|
||||
#if DNS_ZONE_TRACE
|
||||
#define dns_zone_ref(ptr) dns_zone__ref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_zone_unref(ptr) dns_zone__unref(ptr, __func__, __FILE__, __LINE__)
|
||||
|
||||
@@ -1,29 +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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \file dns/zonekey.h */
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
||||
bool
|
||||
dns_zonekey_iszonekey(dns_rdata_t *keyrdata);
|
||||
/*%<
|
||||
* Determines if the key record contained in the rdata is a zone key.
|
||||
*
|
||||
* Requires:
|
||||
* 'keyrdata' is not NULL.
|
||||
*/
|
||||
@@ -460,10 +460,6 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory);
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp);
|
||||
isc_result_t
|
||||
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
|
||||
/*%<
|
||||
|
||||
+70
-39
@@ -189,13 +189,19 @@ dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first) {
|
||||
isc_stdtime_t zrrsig_present;
|
||||
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
||||
zrrsig_present = published + ttlsig +
|
||||
dns_kasp_zonepropagationdelay(kasp) +
|
||||
dns_kasp_publishsafety(kasp);
|
||||
dns_kasp_zonepropagationdelay(kasp);
|
||||
if (zrrsig_present > syncpublish) {
|
||||
syncpublish = zrrsig_present;
|
||||
}
|
||||
}
|
||||
dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncpublish);
|
||||
|
||||
uint32_t lifetime = 0;
|
||||
ret = dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
|
||||
if (ret == ISC_R_SUCCESS && lifetime > 0) {
|
||||
dst_key_settime(key, DST_TIME_SYNCDELETE,
|
||||
(syncpublish + lifetime));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -243,6 +249,17 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
pub = now;
|
||||
}
|
||||
|
||||
/*
|
||||
* To calculate phase out times ("Retired", "Removed", ...),
|
||||
* the key lifetime is required.
|
||||
*/
|
||||
uint32_t klifetime = 0;
|
||||
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
|
||||
klifetime = lifetime;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate prepublication time.
|
||||
*/
|
||||
@@ -272,13 +289,16 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp,
|
||||
true);
|
||||
syncpub2 = pub + ttlsig +
|
||||
dns_kasp_publishsafety(kasp) +
|
||||
dns_kasp_zonepropagationdelay(kasp);
|
||||
}
|
||||
|
||||
syncpub = ISC_MAX(syncpub1, syncpub2);
|
||||
dst_key_settime(key->key, DST_TIME_SYNCPUBLISH,
|
||||
syncpub);
|
||||
if (klifetime > 0) {
|
||||
dst_key_settime(key->key, DST_TIME_SYNCDELETE,
|
||||
(syncpub + klifetime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,13 +311,6 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
|
||||
ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
uint32_t klifetime = 0;
|
||||
|
||||
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
|
||||
klifetime = lifetime;
|
||||
}
|
||||
if (klifetime == 0) {
|
||||
/*
|
||||
* No inactive time and no lifetime,
|
||||
@@ -398,7 +411,7 @@ keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
/* Initialize lifetime. */
|
||||
if (r != ISC_R_SUCCESS) {
|
||||
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
|
||||
return;
|
||||
l = lifetime - 1;
|
||||
}
|
||||
/* Skip keys that are still hidden or already retiring. */
|
||||
if (g != OMNIPRESENT) {
|
||||
@@ -420,6 +433,7 @@ keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
|
||||
} else {
|
||||
dst_key_unsettime(key->key, DST_TIME_INACTIVE);
|
||||
dst_key_unsettime(key->key, DST_TIME_DELETE);
|
||||
dst_key_unsettime(key->key, DST_TIME_SYNCDELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1286,6 +1300,7 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
isc_result_t ret;
|
||||
isc_stdtime_t lastchange, dstime, nexttime = now;
|
||||
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
|
||||
uint32_t dsstate;
|
||||
|
||||
/*
|
||||
* No need to wait if we move things into an uncertain state.
|
||||
@@ -1355,15 +1370,12 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
* records. This translates to:
|
||||
*
|
||||
* Dsgn + zone-propagation-delay + max-zone-ttl.
|
||||
*
|
||||
* We will also add the retire-safety interval.
|
||||
*/
|
||||
nexttime = lastchange + ttlsig +
|
||||
dns_kasp_zonepropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
dns_kasp_zonepropagationdelay(kasp);
|
||||
/*
|
||||
* Only add the sign delay Dsgn if there is an actual
|
||||
* predecessor or successor key.
|
||||
* Only add the sign delay Dsgn and retire-safety if
|
||||
* there is an actual predecessor or successor key.
|
||||
*/
|
||||
uint32_t tag;
|
||||
ret = dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
|
||||
@@ -1373,7 +1385,8 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
DST_NUM_SUCCESSOR, &tag);
|
||||
}
|
||||
if (ret == ISC_R_SUCCESS) {
|
||||
nexttime += dns_kasp_signdelay(kasp);
|
||||
nexttime += dns_kasp_signdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1399,35 +1412,36 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
|
||||
* This translates to:
|
||||
*
|
||||
* parent-propagation-delay + parent-ds-ttl.
|
||||
*
|
||||
* We will also add the retire-safety interval.
|
||||
*/
|
||||
case OMNIPRESENT:
|
||||
/* Make sure DS has been seen in the parent. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_DSPUBLISH,
|
||||
&dstime);
|
||||
if (ret != ISC_R_SUCCESS || dstime > now) {
|
||||
/* Not yet, try again in an hour. */
|
||||
nexttime = now + 3600;
|
||||
} else {
|
||||
nexttime =
|
||||
dstime + dns_kasp_dsttl(kasp) +
|
||||
dns_kasp_parentpropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
break;
|
||||
case HIDDEN:
|
||||
/* Make sure DS has been withdrawn from the parent. */
|
||||
ret = dst_key_gettime(key->key, DST_TIME_DSDELETE,
|
||||
&dstime);
|
||||
/* Make sure DS has been seen in/withdrawn from the
|
||||
* parent. */
|
||||
dsstate = next_state == HIDDEN ? DST_TIME_DSDELETE
|
||||
: DST_TIME_DSPUBLISH;
|
||||
ret = dst_key_gettime(key->key, dsstate, &dstime);
|
||||
if (ret != ISC_R_SUCCESS || dstime > now) {
|
||||
/* Not yet, try again in an hour. */
|
||||
nexttime = now + 3600;
|
||||
} else {
|
||||
nexttime =
|
||||
dstime + dns_kasp_dsttl(kasp) +
|
||||
dns_kasp_parentpropagationdelay(kasp) +
|
||||
dns_kasp_retiresafety(kasp);
|
||||
dns_kasp_parentpropagationdelay(kasp);
|
||||
/*
|
||||
* Only add the retire-safety if there is an
|
||||
* actual predecessor or successor key.
|
||||
*/
|
||||
uint32_t tag;
|
||||
ret = dst_key_getnum(key->key,
|
||||
DST_NUM_PREDECESSOR, &tag);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
ret = dst_key_getnum(key->key,
|
||||
DST_NUM_SUCCESSOR,
|
||||
&tag);
|
||||
}
|
||||
if (ret == ISC_R_SUCCESS) {
|
||||
nexttime += dns_kasp_retiresafety(kasp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1763,7 +1777,9 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
|
||||
if (prepub == 0 || prepub > now) {
|
||||
/* No need to start rollover now. */
|
||||
if (*nexttime == 0 || prepub < *nexttime) {
|
||||
*nexttime = prepub;
|
||||
if (prepub > 0) {
|
||||
*nexttime = prepub;
|
||||
}
|
||||
}
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
@@ -2022,6 +2038,20 @@ keymgr_purge_keyfile(dst_key_t *key, int type) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
dst_key_doublematch(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
|
||||
int matches = 0;
|
||||
|
||||
for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
|
||||
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
|
||||
{
|
||||
if (dns_kasp_key_match(kkey, key)) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
return matches > 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Examine 'keys' and match 'kasp' policy.
|
||||
*
|
||||
@@ -2161,6 +2191,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
|
||||
* matches the kasp policy.
|
||||
*/
|
||||
if (!dst_key_is_unused(dkey->key) &&
|
||||
!dst_key_doublematch(dkey, kasp) &&
|
||||
(dst_key_goal(dkey->key) ==
|
||||
OMNIPRESENT) &&
|
||||
!keymgr_dep(dkey->key, keyring,
|
||||
|
||||
+163
-19
@@ -3105,7 +3105,7 @@ dns_message_checksig_async(dns_message_t *msg, dns_view_t *view,
|
||||
|
||||
isc_result_t
|
||||
dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
isc_buffer_t b, msgb;
|
||||
isc_buffer_t msgb;
|
||||
|
||||
REQUIRE(DNS_MESSAGE_VALID(msg));
|
||||
|
||||
@@ -3126,7 +3126,7 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
return dns_tsig_verify(&msgb, msg, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_t sigrdata = DNS_RDATA_INIT;
|
||||
dns_rdata_sig_t sig;
|
||||
dns_rdataset_t keyset;
|
||||
isc_result_t result;
|
||||
@@ -3134,7 +3134,7 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
|
||||
result = dns_rdataset_first(msg->sig0);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_rdataset_current(msg->sig0, &rdata);
|
||||
dns_rdataset_current(msg->sig0, &sigrdata);
|
||||
|
||||
/*
|
||||
* This can occur when the message is a dynamic update, since
|
||||
@@ -3143,11 +3143,11 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
* looked for in the additional section, and the dynamic update
|
||||
* meta-records are in the prerequisite and update sections.
|
||||
*/
|
||||
if (rdata.length == 0) {
|
||||
if (sigrdata.length == 0) {
|
||||
return ISC_R_UNEXPECTEDEND;
|
||||
}
|
||||
|
||||
result = dns_rdata_tostruct(&rdata, &sig, NULL);
|
||||
result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
@@ -3191,26 +3191,32 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
message_checks < max_message_checks;
|
||||
key_checks++, result = dns_rdataset_next(&keyset))
|
||||
{
|
||||
dns_rdata_t keyrdata = DNS_RDATA_INIT;
|
||||
dns_rdata_key_t ks;
|
||||
dst_key_t *key = NULL;
|
||||
isc_region_t r;
|
||||
|
||||
dns_rdata_reset(&rdata);
|
||||
dns_rdataset_current(&keyset, &rdata);
|
||||
isc_buffer_init(&b, rdata.data, rdata.length);
|
||||
isc_buffer_add(&b, rdata.length);
|
||||
dns_rdataset_current(&keyset, &keyrdata);
|
||||
dns_rdata_tostruct(&keyrdata, &ks, NULL);
|
||||
|
||||
result = dst_key_fromdns(&sig.signer, rdata.rdclass, &b,
|
||||
view->mctx, &key);
|
||||
if (sig.algorithm != ks.algorithm ||
|
||||
(ks.protocol != DNS_KEYPROTO_DNSSEC &&
|
||||
ks.protocol != DNS_KEYPROTO_ANY))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dns_rdata_toregion(&keyrdata, &r);
|
||||
if (dst_region_computeid(&r) != sig.keyid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = dns_dnssec_keyfromrdata(&sig.signer, &keyrdata,
|
||||
view->mctx, &key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
if (dst_key_alg(key) != sig.algorithm ||
|
||||
dst_key_id(key) != sig.keyid ||
|
||||
!(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
|
||||
dst_key_proto(key) == DNS_KEYPROTO_ANY))
|
||||
{
|
||||
dst_key_free(&key);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = dns_dnssec_verifymessage(&msgb, msg, key);
|
||||
dst_key_free(&key);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
@@ -3506,6 +3512,116 @@ static const char *option_names[] = {
|
||||
[DNS_OPT_ZONEVERSION] = "ZONEVERSION",
|
||||
};
|
||||
|
||||
static isc_result_t
|
||||
render_zoneversion(dns_message_t *msg, isc_buffer_t *optbuf,
|
||||
const dns_master_style_t *style, isc_buffer_t *target) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
unsigned int labels = isc_buffer_getuint8(optbuf);
|
||||
unsigned int type = isc_buffer_getuint8(optbuf);
|
||||
char buf[sizeof("4000000000")];
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
dns_name_t *name = ISC_LIST_HEAD(msg->sections[DNS_SECTION_QUESTION]);
|
||||
dns_name_t suffix = DNS_NAME_INITEMPTY;
|
||||
bool yaml = false, rawmode = false;
|
||||
const char *sep1 = " ", *sep2 = ", ";
|
||||
|
||||
if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) {
|
||||
msg->indent.count++;
|
||||
sep1 = sep2 = "\n";
|
||||
yaml = true;
|
||||
}
|
||||
|
||||
ADD_STRING(target, sep1);
|
||||
|
||||
if (msg->counts[DNS_SECTION_QUESTION] != 1 || name == NULL ||
|
||||
dns_name_countlabels(name) < labels + 1)
|
||||
{
|
||||
rawmode = true;
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "LABELS: ");
|
||||
snprintf(buf, sizeof(buf), "%u", labels);
|
||||
ADD_STRING(target, buf);
|
||||
} else {
|
||||
dns_name_split(name, labels + 1, NULL, &suffix);
|
||||
dns_name_format(&suffix, namebuf, sizeof(namebuf));
|
||||
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "ZONE: ");
|
||||
if (yaml) {
|
||||
char *s = namebuf;
|
||||
ADD_STRING(target, "\"");
|
||||
while (*s != 0) {
|
||||
if (*s == '\\' || *s == '"') {
|
||||
ADD_STRING(target, "\\");
|
||||
}
|
||||
if (isc_buffer_availablelength(target) < 1) {
|
||||
result = ISC_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_putmem(target, (unsigned char *)s,
|
||||
1);
|
||||
s++;
|
||||
}
|
||||
ADD_STRING(target, "\"");
|
||||
} else {
|
||||
ADD_STRING(target, namebuf);
|
||||
}
|
||||
}
|
||||
ADD_STRING(target, sep2);
|
||||
|
||||
if (!rawmode && type == 0 && isc_buffer_remaininglength(optbuf) == 4) {
|
||||
uint32_t serial = isc_buffer_getuint32(optbuf);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "SOA-SERIAL: ");
|
||||
snprintf(buf, sizeof(buf), "%u", serial);
|
||||
ADD_STRING(target, buf);
|
||||
} else {
|
||||
size_t len = isc_buffer_remaininglength(optbuf);
|
||||
unsigned char *data = isc_buffer_current(optbuf);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "TYPE: ");
|
||||
snprintf(buf, sizeof(buf), "%u", type);
|
||||
ADD_STRING(target, buf);
|
||||
ADD_STRING(target, sep2);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "VALUE: ");
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
snprintf(buf, sizeof(buf), "%02x", data[i]);
|
||||
ADD_STRING(target, buf);
|
||||
}
|
||||
if (yaml) {
|
||||
ADD_STRING(target, sep2);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "PVALUE: \"");
|
||||
} else {
|
||||
ADD_STRING(target, " (\"");
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (isprint(data[i])) {
|
||||
if (yaml && (data[i] == '\\' || data[i] == '"'))
|
||||
{
|
||||
ADD_STRING(target, "\\");
|
||||
}
|
||||
if (isc_buffer_availablelength(target) < 1) {
|
||||
result = ISC_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_putmem(target, &data[i], 1);
|
||||
} else {
|
||||
ADD_STRING(target, ".");
|
||||
}
|
||||
}
|
||||
if (yaml) {
|
||||
ADD_STRING(target, "\"");
|
||||
} else {
|
||||
ADD_STRING(target, "\")");
|
||||
}
|
||||
isc_buffer_forward(optbuf, len);
|
||||
}
|
||||
cleanup:
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
|
||||
const dns_master_style_t *style,
|
||||
@@ -3783,6 +3899,20 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
|
||||
optbuf = sb;
|
||||
}
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (optlen >= 2U) {
|
||||
isc_buffer_t zonebuf = optbuf;
|
||||
isc_buffer_setactive(&zonebuf, optlen);
|
||||
result = render_zoneversion(
|
||||
msg, &zonebuf, style, target);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
ADD_STRING(target, "\n");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -4202,6 +4332,20 @@ dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section,
|
||||
optbuf = sb;
|
||||
}
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (optlen >= 2U) {
|
||||
isc_buffer_t zonebuf = optbuf;
|
||||
isc_buffer_setactive(&zonebuf, optlen);
|
||||
result = render_zoneversion(
|
||||
msg, &zonebuf, style, target);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
ADD_STRING(target, "\n");
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+5
-1
@@ -57,6 +57,7 @@ struct dns_peer {
|
||||
bool request_ixfr;
|
||||
bool support_edns;
|
||||
bool request_nsid;
|
||||
bool request_zoneversion;
|
||||
bool send_cookie;
|
||||
bool require_cookie;
|
||||
bool request_expire;
|
||||
@@ -98,7 +99,8 @@ enum {
|
||||
SERVER_PADDING_BIT,
|
||||
REQUEST_TCP_KEEPALIVE_BIT,
|
||||
REQUIRE_COOKIE_BIT,
|
||||
DNS_PEER_FLAGS_COUNT
|
||||
DNS_PEER_FLAGS_COUNT,
|
||||
REQUEST_ZONEVERSION
|
||||
};
|
||||
|
||||
STATIC_ASSERT(DNS_PEER_FLAGS_COUNT <= CHAR_BIT * sizeof(uint32_t),
|
||||
@@ -382,6 +384,8 @@ ACCESS_OPTION(requestixfr, REQUEST_IXFR_BIT, bool, request_ixfr)
|
||||
ACCESS_OPTION(requestixfrmaxdiffs, REQUEST_IXFRMAXDIFFS_BIT, uint32_t,
|
||||
request_ixfr_maxdiffs)
|
||||
ACCESS_OPTION(requestnsid, REQUEST_NSID_BIT, bool, request_nsid)
|
||||
ACCESS_OPTION(requestzoneversion, REQUEST_ZONEVERSION, bool,
|
||||
request_zoneversion)
|
||||
ACCESS_OPTION(requirecookie, REQUIRE_COOKIE_BIT, bool, require_cookie)
|
||||
ACCESS_OPTION(sendcookie, SEND_COOKIE_BIT, bool, send_cookie)
|
||||
ACCESS_OPTION(supportedns, SUPPORT_EDNS_BIT, bool, support_edns)
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
#include <dns/stats.h>
|
||||
#include <dns/time.h>
|
||||
#include <dns/view.h>
|
||||
#include <dns/zonekey.h>
|
||||
|
||||
#include "db_p.h"
|
||||
#include "qpcache_p.h"
|
||||
|
||||
+7
-16
@@ -43,6 +43,7 @@
|
||||
#include <dns/callbacks.h>
|
||||
#include <dns/db.h>
|
||||
#include <dns/dbiterator.h>
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/masterdump.h>
|
||||
#include <dns/name.h>
|
||||
@@ -58,7 +59,6 @@
|
||||
#include <dns/time.h>
|
||||
#include <dns/view.h>
|
||||
#include <dns/zone.h>
|
||||
#include <dns/zonekey.h>
|
||||
|
||||
#include "db_p.h"
|
||||
#include "qpzone_p.h"
|
||||
@@ -1143,25 +1143,17 @@ setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) {
|
||||
bool hasnsec = false;
|
||||
isc_result_t result;
|
||||
|
||||
version->secure = false;
|
||||
version->havensec3 = false;
|
||||
|
||||
dns_rdataset_init(&keyset);
|
||||
result = dns_db_findrdataset(db, origin, (dns_dbversion_t *)version,
|
||||
dns_rdatatype_dnskey, 0, 0, &keyset, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = dns_rdataset_first(&keyset);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdata_t keyrdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&keyset, &keyrdata);
|
||||
if (dns_zonekey_iszonekey(&keyrdata)) {
|
||||
haszonekey = true;
|
||||
break;
|
||||
}
|
||||
result = dns_rdataset_next(&keyset);
|
||||
}
|
||||
haszonekey = dns_dnssec_haszonekey(&keyset);
|
||||
dns_rdataset_disassociate(&keyset);
|
||||
}
|
||||
if (!haszonekey) {
|
||||
version->secure = false;
|
||||
version->havensec3 = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1181,12 +1173,11 @@ setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) {
|
||||
setnsec3parameters(db, version);
|
||||
|
||||
/*
|
||||
* Do we have a valid NSEC/NSEC3 chain?
|
||||
* If we don't have a valid NSEC/NSEC3 chain,
|
||||
* clear the secure flag.
|
||||
*/
|
||||
if (version->havensec3 || hasnsec) {
|
||||
version->secure = true;
|
||||
} else {
|
||||
version->secure = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,6 +266,21 @@ fromwire_opt(ARGS_FROMWIRE) {
|
||||
}
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (length == 0) {
|
||||
/* Request */
|
||||
break;
|
||||
}
|
||||
/* Labels and Type */
|
||||
if (length < 2) {
|
||||
return DNS_R_OPTERR;
|
||||
}
|
||||
/* Type 0 (serial), length is 6. */
|
||||
if (sregion.base[1] == 0 && length != 6) {
|
||||
return DNS_R_OPTERR;
|
||||
}
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
default:
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
|
||||
+215
-106
@@ -24,6 +24,7 @@
|
||||
#include <isc/counter.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/hashmap.h>
|
||||
#include <isc/hex.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/loop.h>
|
||||
#include <isc/mutex.h>
|
||||
@@ -471,8 +472,8 @@ struct fetchctx {
|
||||
unsigned int depth;
|
||||
char clientstr[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
||||
uint32_t nvalidations;
|
||||
uint32_t nfails;
|
||||
isc_counter_t *nvalidations;
|
||||
isc_counter_t *nfails;
|
||||
};
|
||||
|
||||
#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
|
||||
@@ -802,10 +803,6 @@ typedef struct respctx {
|
||||
* listening for the correct one */
|
||||
bool truncated; /* response was truncated */
|
||||
bool no_response; /* no response was received */
|
||||
bool glue_in_answer; /* glue may be in the answer
|
||||
* section */
|
||||
bool ns_in_answer; /* NS may be in the answer
|
||||
* section */
|
||||
bool negative; /* is this a negative response? */
|
||||
|
||||
isc_stdtime_t now; /* time info */
|
||||
@@ -977,8 +974,8 @@ valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
|
||||
|
||||
result = dns_validator_create(
|
||||
fctx->res->view, name, type, rdataset, sigrdataset, message,
|
||||
valoptions, fctx->loop, validated, valarg, &fctx->nvalidations,
|
||||
&fctx->nfails, fctx->qc, fctx->gqc, &fctx->edectx, &validator);
|
||||
valoptions, fctx->loop, validated, valarg, fctx->nvalidations,
|
||||
fctx->nfails, fctx->qc, fctx->gqc, &fctx->edectx, &validator);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
inc_stats(fctx->res, dns_resstatscounter_val);
|
||||
ISC_LIST_APPEND(fctx->validators, validator, link);
|
||||
@@ -2508,6 +2505,7 @@ resquery_send(resquery_t *query) {
|
||||
unsigned int flags = query->addrinfo->flags;
|
||||
bool reqnsid = res->view->requestnsid;
|
||||
bool sendcookie = res->view->sendcookie;
|
||||
bool reqzoneversion = res->view->requestzoneversion;
|
||||
bool tcpkeepalive = false;
|
||||
unsigned char cookie[COOKIE_BUFFER_SIZE];
|
||||
uint16_t padding = 0;
|
||||
@@ -2550,8 +2548,6 @@ resquery_send(resquery_t *query) {
|
||||
*/
|
||||
if (peer != NULL) {
|
||||
uint8_t ednsversion;
|
||||
(void)dns_peer_getrequestnsid(peer, &reqnsid);
|
||||
(void)dns_peer_getsendcookie(peer, &sendcookie);
|
||||
result = dns_peer_getednsversion(peer,
|
||||
&ednsversion);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
@@ -2559,6 +2555,10 @@ resquery_send(resquery_t *query) {
|
||||
{
|
||||
version = ednsversion;
|
||||
}
|
||||
(void)dns_peer_getrequestnsid(peer, &reqnsid);
|
||||
(void)dns_peer_getrequestzoneversion(
|
||||
peer, &reqzoneversion);
|
||||
(void)dns_peer_getsendcookie(peer, &sendcookie);
|
||||
}
|
||||
if (NOCOOKIE(query->addrinfo)) {
|
||||
sendcookie = false;
|
||||
@@ -2570,6 +2570,13 @@ resquery_send(resquery_t *query) {
|
||||
ednsopts[ednsopt].value = NULL;
|
||||
ednsopt++;
|
||||
}
|
||||
if (reqzoneversion) {
|
||||
INSIST(ednsopt < DNS_EDNSOPTIONS);
|
||||
ednsopts[ednsopt].code = DNS_OPT_ZONEVERSION;
|
||||
ednsopts[ednsopt].length = 0;
|
||||
ednsopts[ednsopt].value = NULL;
|
||||
ednsopt++;
|
||||
}
|
||||
if (sendcookie) {
|
||||
INSIST(ednsopt < DNS_EDNSOPTIONS);
|
||||
ednsopts[ednsopt].code = DNS_OPT_COOKIE;
|
||||
@@ -2624,8 +2631,14 @@ resquery_send(resquery_t *query) {
|
||||
query->ednsversion = version;
|
||||
result = fctx_addopt(fctx->qmessage, version, udpsize,
|
||||
ednsopts, ednsopt);
|
||||
if (reqnsid && result == ISC_R_SUCCESS) {
|
||||
query->options |= DNS_FETCHOPT_WANTNSID;
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (reqnsid) {
|
||||
query->options |= DNS_FETCHOPT_WANTNSID;
|
||||
}
|
||||
if (reqzoneversion) {
|
||||
query->options |=
|
||||
DNS_FETCHOPT_WANTZONEVERSION;
|
||||
}
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* We couldn't add the OPT, but we'll
|
||||
@@ -4504,6 +4517,12 @@ fctx_destroy(fetchctx_t *fctx) {
|
||||
isc_mem_put(fctx->mctx, sa, sizeof(*sa));
|
||||
}
|
||||
|
||||
if (fctx->nfails != NULL) {
|
||||
isc_counter_detach(&fctx->nfails);
|
||||
}
|
||||
if (fctx->nvalidations != NULL) {
|
||||
isc_counter_detach(&fctx->nvalidations);
|
||||
}
|
||||
isc_counter_detach(&fctx->qc);
|
||||
if (fctx->gqc != NULL) {
|
||||
isc_counter_detach(&fctx->gqc);
|
||||
@@ -4673,6 +4692,8 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
||||
char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1];
|
||||
isc_mem_t *mctx = isc_loop_getmctx(loop);
|
||||
size_t p;
|
||||
uint32_t nvalidations = atomic_load_relaxed(&res->maxvalidations);
|
||||
uint32_t nfails = atomic_load_relaxed(&res->maxvalidationfails);
|
||||
|
||||
/*
|
||||
* Caller must be holding the lock for 'bucket'
|
||||
@@ -4691,8 +4712,6 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
||||
.fwdpolicy = dns_fwdpolicy_none,
|
||||
.result = ISC_R_FAILURE,
|
||||
.loop = loop,
|
||||
.nvalidations = atomic_load_relaxed(&res->maxvalidations),
|
||||
.nfails = atomic_load_relaxed(&res->maxvalidationfails),
|
||||
};
|
||||
|
||||
isc_mem_attach(mctx, &fctx->mctx);
|
||||
@@ -4714,6 +4733,14 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
||||
|
||||
FCTXTRACE("create");
|
||||
|
||||
if (nfails > 0) {
|
||||
isc_counter_create(mctx, nfails, &fctx->nfails);
|
||||
}
|
||||
|
||||
if (nvalidations > 0) {
|
||||
isc_counter_create(mctx, nvalidations, &fctx->nvalidations);
|
||||
}
|
||||
|
||||
if (qc != NULL) {
|
||||
isc_counter_attach(qc, &fctx->qc);
|
||||
isc_log_write(DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER,
|
||||
@@ -4946,6 +4973,12 @@ cleanup_nameservers:
|
||||
dns_rdataset_disassociate(&fctx->nameservers);
|
||||
}
|
||||
isc_mem_free(fctx->mctx, fctx->info);
|
||||
if (fctx->nfails != NULL) {
|
||||
isc_counter_detach(&fctx->nfails);
|
||||
}
|
||||
if (fctx->nvalidations != NULL) {
|
||||
isc_counter_detach(&fctx->nvalidations);
|
||||
}
|
||||
isc_counter_detach(&fctx->qc);
|
||||
if (fctx->gqc != NULL) {
|
||||
isc_counter_detach(&fctx->gqc);
|
||||
@@ -7371,17 +7404,38 @@ checknames(dns_message_t *message) {
|
||||
checknamessection(message, DNS_SECTION_ADDITIONAL);
|
||||
}
|
||||
|
||||
static void
|
||||
make_hex(unsigned char *src, size_t srclen, char *buf, size_t buflen) {
|
||||
isc_buffer_t b;
|
||||
isc_region_t r;
|
||||
isc_result_t result;
|
||||
|
||||
r.base = src;
|
||||
r.length = srclen;
|
||||
isc_buffer_init(&b, buf, buflen);
|
||||
result = isc_hex_totext(&r, 0, "", &b);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
isc_buffer_putuint8(&b, '\0');
|
||||
}
|
||||
|
||||
static void
|
||||
make_printable(unsigned char *src, size_t srclen, char *buf, size_t buflen) {
|
||||
INSIST(buflen > srclen);
|
||||
while (srclen-- > 0) {
|
||||
unsigned char c = *src++;
|
||||
*buf++ = isprint(c) ? c : '.';
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Log server NSID at log level 'level'
|
||||
*/
|
||||
static void
|
||||
log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level,
|
||||
isc_mem_t *mctx) {
|
||||
static const char hex[17] = "0123456789abcdef";
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE], *buf = NULL, *pbuf = NULL;
|
||||
size_t buflen;
|
||||
unsigned char *p, *nsid;
|
||||
unsigned char *buf = NULL, *pbuf = NULL;
|
||||
|
||||
REQUIRE(nsid_len <= UINT16_MAX);
|
||||
|
||||
@@ -7391,20 +7445,10 @@ log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level,
|
||||
pbuf = isc_mem_get(mctx, nsid_len + 1);
|
||||
|
||||
/* Convert to hex */
|
||||
p = buf;
|
||||
nsid = isc_buffer_current(opt);
|
||||
for (size_t i = 0; i < nsid_len; i++) {
|
||||
*p++ = hex[(nsid[i] >> 4) & 0xf];
|
||||
*p++ = hex[nsid[i] & 0xf];
|
||||
}
|
||||
*p = '\0';
|
||||
make_hex(isc_buffer_current(opt), nsid_len, buf, buflen);
|
||||
|
||||
/* Make printable version */
|
||||
p = pbuf;
|
||||
for (size_t i = 0; i < nsid_len; i++) {
|
||||
*p++ = isprint(nsid[i]) ? nsid[i] : '.';
|
||||
}
|
||||
*p = '\0';
|
||||
make_printable(isc_buffer_current(opt), nsid_len, pbuf, nsid_len + 1);
|
||||
|
||||
isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
|
||||
sizeof(addrbuf));
|
||||
@@ -7415,13 +7459,106 @@ log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level,
|
||||
isc_mem_put(mctx, buf, buflen);
|
||||
}
|
||||
|
||||
static bool
|
||||
iscname(dns_message_t *message, dns_name_t *name) {
|
||||
isc_result_t result;
|
||||
static void
|
||||
log_zoneversion(unsigned char *version, size_t version_len, unsigned char *nsid,
|
||||
size_t nsid_len, resquery_t *query, int level,
|
||||
isc_mem_t *mctx) {
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
size_t nsid_buflen = 0;
|
||||
char *nsid_buf = NULL;
|
||||
char *nsid_pbuf = NULL;
|
||||
const char *nsid_hex = "";
|
||||
const char *nsid_print = "";
|
||||
const char *sep_1 = "";
|
||||
const char *sep_2 = "";
|
||||
const char *sep_3 = "";
|
||||
dns_name_t suffix = DNS_NAME_INITEMPTY;
|
||||
unsigned int labels;
|
||||
|
||||
result = dns_message_findname(message, DNS_SECTION_ANSWER, name,
|
||||
dns_rdatatype_cname, 0, NULL, NULL);
|
||||
return result == ISC_R_SUCCESS ? true : false;
|
||||
REQUIRE(version_len <= UINT16_MAX);
|
||||
|
||||
/*
|
||||
* Don't log reflected ZONEVERSION option.
|
||||
*/
|
||||
if (version_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enforced by dns_rdata_fromwire. */
|
||||
INSIST(version_len >= 2);
|
||||
|
||||
/*
|
||||
* Sanity check on label count.
|
||||
*/
|
||||
labels = version[0] + 1;
|
||||
if (dns_name_countlabels(query->fctx->name) < labels) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get zone name.
|
||||
*/
|
||||
dns_name_split(query->fctx->name, labels, NULL, &suffix);
|
||||
dns_name_format(&suffix, namebuf, sizeof(namebuf));
|
||||
|
||||
if (nsid != NULL) {
|
||||
nsid_buflen = nsid_len * 2 + 1;
|
||||
nsid_hex = nsid_buf = isc_mem_get(mctx, nsid_buflen);
|
||||
nsid_print = nsid_pbuf = isc_mem_get(mctx, nsid_len + 1);
|
||||
|
||||
/* Convert to hex */
|
||||
make_hex(nsid, nsid_len, nsid_buf, nsid_buflen);
|
||||
|
||||
/* Convert to printable */
|
||||
make_printable(nsid, nsid_len, nsid_pbuf, nsid_len + 1);
|
||||
|
||||
sep_1 = " (NSID ";
|
||||
sep_2 = " (";
|
||||
sep_3 = "))";
|
||||
}
|
||||
|
||||
isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
|
||||
sizeof(addrbuf));
|
||||
if (version[1] == 0 && version_len == 6) {
|
||||
uint32_t serial = version[2] << 24 | version[3] << 2 |
|
||||
version[4] << 8 | version[5];
|
||||
isc_log_write(DNS_LOGCATEGORY_ZONEVERSION,
|
||||
DNS_LOGMODULE_RESOLVER, level,
|
||||
"received ZONEVERSION serial %u from %s for %s "
|
||||
"zone %s%s%s%s%s%s",
|
||||
serial, addrbuf, query->fctx->info, namebuf,
|
||||
sep_1, nsid_hex, sep_2, nsid_print, sep_3);
|
||||
} else {
|
||||
size_t version_buflen = version_len * 2 + 1;
|
||||
char *version_hex = isc_mem_get(mctx, version_buflen);
|
||||
char *version_pbuf = isc_mem_get(mctx, version_len - 1);
|
||||
|
||||
/* Convert to hex */
|
||||
make_hex(version + 2, version_len - 2, version_hex,
|
||||
version_buflen);
|
||||
|
||||
/* Convert to printable */
|
||||
make_printable(version + 2, version_len - 2, version_pbuf,
|
||||
version_len - 1);
|
||||
|
||||
isc_log_write(DNS_LOGCATEGORY_ZONEVERSION,
|
||||
DNS_LOGMODULE_RESOLVER, level,
|
||||
"received ZONEVERSION type %u value %s (%s) from "
|
||||
"%s for %s zone %s%s%s%s%s%s",
|
||||
version[1], version_hex, version_pbuf, addrbuf,
|
||||
query->fctx->info, namebuf, sep_1, nsid_hex,
|
||||
sep_2, nsid_print, sep_3);
|
||||
isc_mem_put(mctx, version_hex, version_buflen);
|
||||
isc_mem_put(mctx, version_pbuf, version_len - 1);
|
||||
}
|
||||
|
||||
if (nsid_pbuf != NULL) {
|
||||
isc_mem_put(mctx, nsid_pbuf, nsid_len + 1);
|
||||
}
|
||||
if (nsid_buf != NULL) {
|
||||
isc_mem_put(mctx, nsid_buf, nsid_buflen);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -7475,10 +7612,12 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
|
||||
QTRACE("response");
|
||||
|
||||
if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) {
|
||||
inc_stats(fctx->res, dns_resstatscounter_responsev4);
|
||||
} else {
|
||||
inc_stats(fctx->res, dns_resstatscounter_responsev6);
|
||||
if (eresult == ISC_R_SUCCESS) {
|
||||
if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) {
|
||||
inc_stats(fctx->res, dns_resstatscounter_responsev4);
|
||||
} else {
|
||||
inc_stats(fctx->res, dns_resstatscounter_responsev6);
|
||||
}
|
||||
}
|
||||
|
||||
rctx = isc_mem_get(fctx->mctx, sizeof(*rctx));
|
||||
@@ -8060,6 +8199,9 @@ rctx_timedout(respctx_t *rctx) {
|
||||
fctx->timeout = true;
|
||||
fctx->timeouts++;
|
||||
|
||||
rctx->no_response = true;
|
||||
rctx->finish = NULL;
|
||||
|
||||
now = isc_time_now();
|
||||
/* netmgr timeouts are accurate to the millisecond */
|
||||
if (isc_time_microdiff(&fctx->expires, &now) < US_PER_MS) {
|
||||
@@ -8070,8 +8212,6 @@ rctx_timedout(respctx_t *rctx) {
|
||||
} else {
|
||||
FCTXTRACE("query timed out; trying next server");
|
||||
/* try next server */
|
||||
rctx->no_response = true;
|
||||
rctx->finish = NULL;
|
||||
rctx->next_server = true;
|
||||
}
|
||||
|
||||
@@ -8181,6 +8321,11 @@ rctx_opt(respctx_t *rctx) {
|
||||
isc_result_t result;
|
||||
bool seen_cookie = false;
|
||||
bool seen_nsid = false;
|
||||
bool seen_zoneversion = false;
|
||||
unsigned char *nsid = NULL;
|
||||
uint16_t nsidlen = 0;
|
||||
unsigned char *zoneversion = NULL;
|
||||
uint16_t zoneversionlen = 0;
|
||||
|
||||
result = dns_rdataset_first(rctx->opt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -8206,7 +8351,8 @@ rctx_opt(respctx_t *rctx) {
|
||||
break;
|
||||
}
|
||||
seen_nsid = true;
|
||||
|
||||
nsid = isc_buffer_current(&optbuf);
|
||||
nsidlen = optlen;
|
||||
if ((query->options & DNS_FETCHOPT_WANTNSID) != 0) {
|
||||
log_nsid(&optbuf, optlen, query, ISC_LOG_INFO,
|
||||
fctx->mctx);
|
||||
@@ -8244,12 +8390,27 @@ rctx_opt(respctx_t *rctx) {
|
||||
optvalue, optlen);
|
||||
}
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (seen_zoneversion) {
|
||||
break;
|
||||
}
|
||||
seen_zoneversion = true;
|
||||
zoneversion = isc_buffer_current(&optbuf);
|
||||
zoneversionlen = optlen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
}
|
||||
INSIST(isc_buffer_remaininglength(&optbuf) == 0U);
|
||||
|
||||
if ((query->options & DNS_FETCHOPT_WANTZONEVERSION) != 0 &&
|
||||
zoneversion != NULL)
|
||||
{
|
||||
log_zoneversion(zoneversion, zoneversionlen, nsid, nsidlen,
|
||||
query, ISC_LOG_INFO, fctx->mctx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8345,20 +8506,6 @@ rctx_answer(respctx_t *rctx) {
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("rctx_answer_positive (AA/fwd)", result);
|
||||
}
|
||||
} else if (iscname(query->rmessage, fctx->name) &&
|
||||
fctx->type != dns_rdatatype_any &&
|
||||
fctx->type != dns_rdatatype_cname)
|
||||
{
|
||||
/*
|
||||
* A BIND8 server could return a non-authoritative
|
||||
* answer when a CNAME is followed. We should treat
|
||||
* it as a valid answer.
|
||||
*/
|
||||
result = rctx_answer_positive(rctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("rctx_answer_positive (!ANY/!CNAME)",
|
||||
result);
|
||||
}
|
||||
} else if (fctx->type != dns_rdatatype_ns && !betterreferral(rctx)) {
|
||||
result = rctx_answer_positive(rctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -8366,41 +8513,12 @@ rctx_answer(respctx_t *rctx) {
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This may be a delegation. First let's check for
|
||||
* This may be a delegation.
|
||||
*/
|
||||
|
||||
if (fctx->type == dns_rdatatype_ns) {
|
||||
/*
|
||||
* A BIND 8 server could incorrectly return a
|
||||
* non-authoritative answer to an NS query
|
||||
* instead of a referral. Since this answer
|
||||
* lacks the SIGs necessary to do DNSSEC
|
||||
* validation, we must invoke the following
|
||||
* special kludge to treat it as a referral.
|
||||
*/
|
||||
rctx->ns_in_answer = true;
|
||||
result = rctx_answer_none(rctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("rctx_answer_none (NS)", result);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Some other servers may still somehow include
|
||||
* an answer when it should return a referral
|
||||
* with an empty answer. Check to see if we can
|
||||
* treat this as a referral by ignoring the
|
||||
* answer. Further more, there may be an
|
||||
* implementation that moves A/AAAA glue records
|
||||
* to the answer section for that type of
|
||||
* delegation when the query is for that glue
|
||||
* record. glue_in_answer will handle
|
||||
* such a corner case.
|
||||
*/
|
||||
rctx->glue_in_answer = true;
|
||||
result = rctx_answer_none(rctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("rctx_answer_none", result);
|
||||
}
|
||||
result = rctx_answer_none(rctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("rctx_answer_none", result);
|
||||
}
|
||||
|
||||
if (result == DNS_R_DELEGATION) {
|
||||
@@ -9006,14 +9124,12 @@ rctx_answer_none(respctx_t *rctx) {
|
||||
rctx->negative = true;
|
||||
}
|
||||
|
||||
if (!rctx->ns_in_answer && !rctx->glue_in_answer) {
|
||||
/*
|
||||
* Process DNSSEC records in the authority section.
|
||||
*/
|
||||
result = rctx_authority_dnssec(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return rctx->result;
|
||||
}
|
||||
/*
|
||||
* Process DNSSEC records in the authority section.
|
||||
*/
|
||||
result = rctx_authority_dnssec(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return rctx->result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9107,12 +9223,7 @@ rctx_authority_negative(respctx_t *rctx) {
|
||||
dns_rdataset_t *rdataset = NULL;
|
||||
bool finished = false;
|
||||
|
||||
if (rctx->ns_in_answer) {
|
||||
INSIST(fctx->type == dns_rdatatype_ns);
|
||||
section = DNS_SECTION_ANSWER;
|
||||
} else {
|
||||
section = DNS_SECTION_AUTHORITY;
|
||||
}
|
||||
section = DNS_SECTION_AUTHORITY;
|
||||
|
||||
result = dns_message_firstname(rctx->query->rmessage, section);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -9271,8 +9382,6 @@ rctx_authority_dnssec(respctx_t *rctx) {
|
||||
dns_rdataset_t *rdataset = NULL;
|
||||
bool finished = false;
|
||||
|
||||
REQUIRE(!rctx->ns_in_answer && !rctx->glue_in_answer);
|
||||
|
||||
result = dns_message_firstname(rctx->query->rmessage,
|
||||
DNS_SECTION_AUTHORITY);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
||||
+52
-52
@@ -1011,59 +1011,46 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
|
||||
static isc_result_t
|
||||
select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) {
|
||||
isc_result_t result;
|
||||
dns_rdata_rrsig_t *siginfo = val->siginfo;
|
||||
isc_buffer_t b;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dst_key_t *oldkey = val->key;
|
||||
bool no_rdata = false;
|
||||
|
||||
if (oldkey == NULL) {
|
||||
if (val->key == NULL) {
|
||||
result = dns_rdataset_first(rdataset);
|
||||
} else {
|
||||
dst_key_free(&oldkey);
|
||||
dst_key_free(&val->key);
|
||||
val->key = NULL;
|
||||
result = dns_rdataset_next(rdataset);
|
||||
}
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto done;
|
||||
if (result == ISC_R_NOMORE) {
|
||||
return ISC_R_NOTFOUND;
|
||||
}
|
||||
|
||||
do {
|
||||
for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) {
|
||||
dns_rdata_rrsig_t *siginfo = val->siginfo;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_dnskey_t key;
|
||||
isc_region_t r;
|
||||
|
||||
dns_rdataset_current(rdataset, &rdata);
|
||||
dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
|
||||
|
||||
isc_buffer_init(&b, rdata.data, rdata.length);
|
||||
isc_buffer_add(&b, rdata.length);
|
||||
INSIST(val->key == NULL);
|
||||
result = dst_key_fromdns_ex(&siginfo->signer, rdata.rdclass, &b,
|
||||
val->view->mctx, no_rdata,
|
||||
&val->key);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (siginfo->algorithm ==
|
||||
(dns_secalg_t)dst_key_alg(val->key) &&
|
||||
siginfo->keyid ==
|
||||
(dns_keytag_t)dst_key_id(val->key) &&
|
||||
(dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) ==
|
||||
0 &&
|
||||
dst_key_iszonekey(val->key))
|
||||
{
|
||||
if (no_rdata) {
|
||||
/* Retry with full key */
|
||||
dns_rdata_reset(&rdata);
|
||||
dst_key_free(&val->key);
|
||||
no_rdata = false;
|
||||
continue;
|
||||
}
|
||||
/* This is the key we're looking for. */
|
||||
goto done;
|
||||
}
|
||||
dst_key_free(&val->key);
|
||||
if (key.algorithm != siginfo->algorithm ||
|
||||
(key.flags & DNS_KEYFLAG_REVOKE) != 0 ||
|
||||
!dns_dnssec_iszonekey(&key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
dns_rdata_reset(&rdata);
|
||||
result = dns_rdataset_next(rdataset);
|
||||
no_rdata = true;
|
||||
} while (result == ISC_R_SUCCESS);
|
||||
|
||||
done:
|
||||
dns_rdata_toregion(&rdata, &r);
|
||||
if (dst_region_computeid(&r) != siginfo->keyid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = dns_dnssec_keyfromrdata(&siginfo->signer, &rdata,
|
||||
val->view->mctx, &val->key);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/* found the key we wanted */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == ISC_R_NOMORE) {
|
||||
result = ISC_R_NOTFOUND;
|
||||
}
|
||||
@@ -1245,7 +1232,10 @@ compute_keytag(dns_rdata_t *rdata) {
|
||||
|
||||
static bool
|
||||
over_max_validations(dns_validator_t *val) {
|
||||
if (val->nvalidations == NULL || (*val->nvalidations) > 0) {
|
||||
if (val->nvalidations == NULL ||
|
||||
isc_counter_used(val->nvalidations) <
|
||||
isc_counter_getlimit(val->nvalidations))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1259,14 +1249,14 @@ consume_validation(dns_validator_t *val) {
|
||||
if (val->nvalidations == NULL) {
|
||||
return;
|
||||
}
|
||||
INSIST((*val->nvalidations) > 0);
|
||||
|
||||
(*val->nvalidations)--;
|
||||
(void)isc_counter_increment(val->nvalidations);
|
||||
}
|
||||
|
||||
static bool
|
||||
over_max_fails(dns_validator_t *val) {
|
||||
if (val->nfails == NULL || (*val->nfails) > 0) {
|
||||
if (val->nfails == NULL ||
|
||||
isc_counter_used(val->nfails) < isc_counter_getlimit(val->nfails))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1280,9 +1270,7 @@ consume_validation_fail(dns_validator_t *val) {
|
||||
if (val->nfails == NULL) {
|
||||
return;
|
||||
}
|
||||
INSIST((*val->nfails) > 0);
|
||||
|
||||
(*val->nfails)--;
|
||||
(void)isc_counter_increment(val->nfails);
|
||||
}
|
||||
|
||||
/*%
|
||||
@@ -3392,7 +3380,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
||||
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
|
||||
dns_message_t *message, unsigned int options,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *arg,
|
||||
uint32_t *nvalidations, uint32_t *nfails,
|
||||
isc_counter_t *nvalidations, isc_counter_t *nfails,
|
||||
isc_counter_t *qc, isc_counter_t *gqc,
|
||||
dns_edectx_t *edectx, dns_validator_t **validatorp) {
|
||||
isc_result_t result = ISC_R_FAILURE;
|
||||
@@ -3424,8 +3412,6 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
||||
.cb = cb,
|
||||
.arg = arg,
|
||||
.rdata = DNS_RDATA_INIT,
|
||||
.nvalidations = nvalidations,
|
||||
.nfails = nfails,
|
||||
.edectx = edectx,
|
||||
};
|
||||
|
||||
@@ -3435,6 +3421,14 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
||||
dns_message_attach(message, &val->message);
|
||||
}
|
||||
|
||||
if (nfails != NULL) {
|
||||
isc_counter_attach(nfails, &val->nfails);
|
||||
}
|
||||
|
||||
if (nvalidations != NULL) {
|
||||
isc_counter_attach(nvalidations, &val->nvalidations);
|
||||
}
|
||||
|
||||
if (qc != NULL) {
|
||||
isc_counter_attach(qc, &val->qc);
|
||||
}
|
||||
@@ -3527,6 +3521,12 @@ destroy_validator(dns_validator_t *val) {
|
||||
if (val->message != NULL) {
|
||||
dns_message_detach(&val->message);
|
||||
}
|
||||
if (val->nfails != NULL) {
|
||||
isc_counter_detach(&val->nfails);
|
||||
}
|
||||
if (val->nvalidations != NULL) {
|
||||
isc_counter_detach(&val->nvalidations);
|
||||
}
|
||||
if (val->qc != NULL) {
|
||||
isc_counter_detach(&val->qc);
|
||||
}
|
||||
|
||||
+110
-46
@@ -1497,6 +1497,56 @@ dns_zone_getserial(dns_zone_t *zone, uint32_t *serialp) {
|
||||
return result;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getzoneversion(dns_zone_t *zone, isc_buffer_t *b) {
|
||||
isc_result_t result = DNS_R_NOTLOADED;
|
||||
unsigned int soacount;
|
||||
uint32_t serial;
|
||||
dns_zone_t *mayberaw = zone;
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(b != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
if (zone->raw != NULL) {
|
||||
LOCK_ZONE(zone->raw);
|
||||
mayberaw = zone->raw;
|
||||
}
|
||||
ZONEDB_LOCK(&mayberaw->dblock, isc_rwlocktype_read);
|
||||
if (DNS_ZONE_OPTION(mayberaw, DNS_ZONEOPT_ZONEVERSION) &&
|
||||
mayberaw->db != NULL)
|
||||
{
|
||||
result = dns_db_getzoneversion(mayberaw->db, b);
|
||||
if (result == ISC_R_NOTIMPLEMENTED) {
|
||||
result = zone_get_from_db(mayberaw, mayberaw->db, NULL,
|
||||
&soacount, NULL, &serial,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS && soacount == 0) {
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (isc_buffer_availablelength(b) >= 6) {
|
||||
isc_buffer_putuint8(
|
||||
b, dns_name_countlabels(
|
||||
&mayberaw->origin) -
|
||||
1);
|
||||
isc_buffer_putuint8(b, 0);
|
||||
isc_buffer_putuint32(b, serial);
|
||||
} else {
|
||||
result = ISC_R_NOSPACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ZONEDB_UNLOCK(&mayberaw->dblock, isc_rwlocktype_read);
|
||||
if (zone->raw != NULL) {
|
||||
UNLOCK_ZONE(zone->raw);
|
||||
}
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Single shot.
|
||||
*/
|
||||
@@ -5998,106 +6048,123 @@ dns_zone_getkeyopts(dns_zone_t *zone) {
|
||||
return atomic_load_relaxed(&zone->keyopts);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(xfrsource != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->xfrsource4 = *xfrsource;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getxfrsource4(dns_zone_t *zone) {
|
||||
void
|
||||
dns_zone_getxfrsource4(dns_zone_t *zone, isc_sockaddr_t *xfrsource) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
return &zone->xfrsource4;
|
||||
REQUIRE(xfrsource != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
*xfrsource = zone->xfrsource4;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(xfrsource != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->xfrsource6 = *xfrsource;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getxfrsource6(dns_zone_t *zone) {
|
||||
void
|
||||
dns_zone_getxfrsource6(dns_zone_t *zone, isc_sockaddr_t *xfrsource) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
return &zone->xfrsource6;
|
||||
REQUIRE(xfrsource != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
*xfrsource = zone->xfrsource6;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(parentalsrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->parentalsrc4 = *parentalsrc;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getparentalsrc4(dns_zone_t *zone) {
|
||||
void
|
||||
dns_zone_getparentalsrc4(dns_zone_t *zone, isc_sockaddr_t *parentalsrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
return &zone->parentalsrc4;
|
||||
REQUIRE(parentalsrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
*parentalsrc = zone->parentalsrc4;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->parentalsrc6 = *parentalsrc;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getparentalsrc6(dns_zone_t *zone) {
|
||||
void
|
||||
dns_zone_getparentalsrc6(dns_zone_t *zone, isc_sockaddr_t *parentalsrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
return &zone->parentalsrc6;
|
||||
REQUIRE(parentalsrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
*parentalsrc = zone->parentalsrc6;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(notifysrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->notifysrc4 = *notifysrc;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getnotifysrc4(dns_zone_t *zone) {
|
||||
void
|
||||
dns_zone_getnotifysrc4(dns_zone_t *zone, isc_sockaddr_t *notifysrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
return &zone->notifysrc4;
|
||||
REQUIRE(notifysrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
*notifysrc = zone->notifysrc4;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
void
|
||||
dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(notifysrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
zone->notifysrc6 = *notifysrc;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_sockaddr_t *
|
||||
dns_zone_getnotifysrc6(dns_zone_t *zone) {
|
||||
void
|
||||
dns_zone_getnotifysrc6(dns_zone_t *zone, isc_sockaddr_t *notifysrc) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
return &zone->notifysrc6;
|
||||
REQUIRE(notifysrc != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
*notifysrc = zone->notifysrc6;
|
||||
UNLOCK_ZONE(zone);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -18371,31 +18438,28 @@ dns_zone_getsigresigninginterval(dns_zone_t *zone) {
|
||||
return zone->sigresigninginterval;
|
||||
}
|
||||
|
||||
isc_sockaddr_t
|
||||
dns_zone_getsourceaddr(dns_zone_t *zone) {
|
||||
isc_sockaddr_t sourceaddr;
|
||||
|
||||
void
|
||||
dns_zone_getsourceaddr(dns_zone_t *zone, isc_sockaddr_t *sourceaddr) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(sourceaddr != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
INSIST(dns_remote_count(&zone->primaries) > 0);
|
||||
sourceaddr = zone->sourceaddr;
|
||||
*sourceaddr = zone->sourceaddr;
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return sourceaddr;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *dest) {
|
||||
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *primaryaddr) {
|
||||
isc_result_t result = ISC_R_NOMORE;
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(dest != NULL);
|
||||
REQUIRE(primaryaddr != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
INSIST(dns_remote_count(&zone->primaries) > 0);
|
||||
if (!dns_remote_done(&zone->primaries)) {
|
||||
*dest = dns_remote_curraddr(&zone->primaries);
|
||||
*primaryaddr = dns_remote_curraddr(&zone->primaries);
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
@@ -1,54 +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.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/result.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/keyvalues.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdatastruct.h>
|
||||
#include <dns/types.h>
|
||||
#include <dns/zonekey.h>
|
||||
|
||||
bool
|
||||
dns_zonekey_iszonekey(dns_rdata_t *keyrdata) {
|
||||
isc_result_t result;
|
||||
dns_rdata_dnskey_t key;
|
||||
bool iszonekey = true;
|
||||
|
||||
REQUIRE(keyrdata != NULL);
|
||||
|
||||
result = dns_rdata_tostruct(keyrdata, &key, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((key.flags & DNS_KEYTYPE_NOAUTH) != 0) {
|
||||
iszonekey = false;
|
||||
}
|
||||
if ((key.flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
|
||||
iszonekey = false;
|
||||
}
|
||||
if (key.protocol != DNS_KEYPROTO_DNSSEC &&
|
||||
key.protocol != DNS_KEYPROTO_ANY)
|
||||
{
|
||||
iszonekey = false;
|
||||
}
|
||||
|
||||
return iszonekey;
|
||||
}
|
||||
@@ -26,6 +26,7 @@ libisc_la_HEADERS = \
|
||||
include/isc/file.h \
|
||||
include/isc/formatcheck.h \
|
||||
include/isc/fuzz.h \
|
||||
include/isc/fxhash.h \
|
||||
include/isc/getaddresses.h \
|
||||
include/isc/hash.h \
|
||||
include/isc/hashmap.h \
|
||||
|
||||
@@ -131,18 +131,28 @@ isc__ascii_load8(const uint8_t *ptr) {
|
||||
* Compare `len` bytes at `a` and `b` for case-insensitive equality
|
||||
*/
|
||||
static inline bool
|
||||
isc_ascii_lowerequal(const uint8_t *a, const uint8_t *b, unsigned int len) {
|
||||
isc_ascii_lowerequal(const uint8_t *restrict a, const uint8_t *restrict b,
|
||||
unsigned int len) {
|
||||
uint64_t a8 = 0, b8 = 0;
|
||||
while (len >= 8) {
|
||||
a8 = isc_ascii_tolower8(isc__ascii_load8(a));
|
||||
b8 = isc_ascii_tolower8(isc__ascii_load8(b));
|
||||
if (a8 != b8) {
|
||||
return false;
|
||||
if (len >= 8) {
|
||||
const uint8_t *a_tail = a + len - 8;
|
||||
const uint8_t *b_tail = b + len - 8;
|
||||
while (len >= 8) {
|
||||
a8 = isc_ascii_tolower8(isc__ascii_load8(a));
|
||||
b8 = isc_ascii_tolower8(isc__ascii_load8(b));
|
||||
if (a8 != b8) {
|
||||
return false;
|
||||
}
|
||||
len -= 8;
|
||||
a += 8;
|
||||
b += 8;
|
||||
}
|
||||
len -= 8;
|
||||
a += 8;
|
||||
b += 8;
|
||||
|
||||
a8 = isc_ascii_tolower8(isc__ascii_load8(a_tail));
|
||||
b8 = isc_ascii_tolower8(isc__ascii_load8(b_tail));
|
||||
return a8 == b8;
|
||||
}
|
||||
|
||||
while (len-- > 0) {
|
||||
if (isc_ascii_tolower(*a++) != isc_ascii_tolower(*b++)) {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the “Software”), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* The constant K from Rust's fxhash */
|
||||
#define K 0x9e3779b97f4a7c15ull
|
||||
|
||||
static inline size_t
|
||||
rotate_left(size_t x, unsigned int n) {
|
||||
return (x << n) | (x >> (sizeof(size_t) * 8 - n));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
fx_add_to_hash(size_t hash, size_t i) {
|
||||
return rotate_left(hash, 5) ^ i * K;
|
||||
}
|
||||
|
||||
/*
|
||||
* Beware: this implementation will use an approximate conversion to lowercase.
|
||||
* This is ok as fxhash is already not hash-flooding resistant and we use it
|
||||
* only for config parsing.
|
||||
*/
|
||||
static inline size_t
|
||||
fx_hash_bytes(size_t initial_hash, const uint8_t *restrict bytes, size_t len,
|
||||
bool case_sensitive) {
|
||||
size_t hash = initial_hash;
|
||||
size_t case_mask = case_sensitive
|
||||
? -1ull
|
||||
: (0b11011111 * 0x0101010101010101ull);
|
||||
|
||||
while (len >= sizeof(size_t)) {
|
||||
size_t value;
|
||||
memmove(&value, bytes, sizeof(size_t));
|
||||
hash = fx_add_to_hash(hash, value & case_mask);
|
||||
bytes += sizeof(size_t);
|
||||
len -= sizeof(size_t);
|
||||
}
|
||||
|
||||
/* Will be ignored if sizeof(size_t) <= 4 */
|
||||
if (len >= 4) {
|
||||
uint32_t value;
|
||||
memmove(&value, bytes, sizeof(uint32_t));
|
||||
hash = fx_add_to_hash(hash, value & case_mask);
|
||||
bytes += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
/* Will be ignored if sizeof(size_t) <= 2 */
|
||||
if (len >= 2) {
|
||||
uint16_t value;
|
||||
memmove(&value, bytes, sizeof(uint16_t));
|
||||
hash = fx_add_to_hash(hash, value & case_mask);
|
||||
bytes += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len >= 1) {
|
||||
hash = fx_add_to_hash(hash, bytes[0] & case_mask);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
+22
-21
@@ -119,36 +119,37 @@ enum isc_logcategory {
|
||||
NAMED_LOGCATEGORY_GENERAL = ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGCATEGORY_SSLKEYLOG,
|
||||
/* dns categories */
|
||||
DNS_LOGCATEGORY_NOTIFY,
|
||||
DNS_LOGCATEGORY_CNAME,
|
||||
DNS_LOGCATEGORY_DATABASE,
|
||||
DNS_LOGCATEGORY_SECURITY,
|
||||
DNS_LOGCATEGORY_DISPATCH,
|
||||
DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGCATEGORY_DNSTAP,
|
||||
DNS_LOGCATEGORY_EDNS_DISABLED,
|
||||
DNS_LOGCATEGORY_LAME_SERVERS,
|
||||
DNS_LOGCATEGORY_NOTIFY,
|
||||
DNS_LOGCATEGORY_NSID,
|
||||
DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGCATEGORY_RPZ,
|
||||
DNS_LOGCATEGORY_RPZ_PASSTHRU,
|
||||
DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGCATEGORY_SECURITY,
|
||||
DNS_LOGCATEGORY_SPILL,
|
||||
DNS_LOGCATEGORY_UPDATE_POLICY,
|
||||
DNS_LOGCATEGORY_XFER_IN,
|
||||
DNS_LOGCATEGORY_XFER_OUT,
|
||||
DNS_LOGCATEGORY_DISPATCH,
|
||||
DNS_LOGCATEGORY_LAME_SERVERS,
|
||||
DNS_LOGCATEGORY_EDNS_DISABLED,
|
||||
DNS_LOGCATEGORY_RPZ,
|
||||
DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGCATEGORY_CNAME,
|
||||
DNS_LOGCATEGORY_SPILL,
|
||||
DNS_LOGCATEGORY_DNSTAP,
|
||||
DNS_LOGCATEGORY_ZONELOAD,
|
||||
DNS_LOGCATEGORY_NSID,
|
||||
DNS_LOGCATEGORY_RPZ_PASSTHRU,
|
||||
DNS_LOGCATEGORY_UPDATE_POLICY,
|
||||
DNS_LOGCATEGORY_ZONEVERSION,
|
||||
/* ns categories */
|
||||
NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGCATEGORY_NETWORK,
|
||||
NS_LOGCATEGORY_UPDATE,
|
||||
NS_LOGCATEGORY_QUERIES,
|
||||
NS_LOGCATEGORY_UPDATE_SECURITY,
|
||||
NS_LOGCATEGORY_QUERY_ERRORS,
|
||||
NS_LOGCATEGORY_TAT,
|
||||
NS_LOGCATEGORY_SERVE_STALE,
|
||||
NS_LOGCATEGORY_RESPONSES,
|
||||
NS_LOGCATEGORY_DRA,
|
||||
NS_LOGCATEGORY_NETWORK,
|
||||
NS_LOGCATEGORY_QUERIES,
|
||||
NS_LOGCATEGORY_QUERY_ERRORS,
|
||||
NS_LOGCATEGORY_RESPONSES,
|
||||
NS_LOGCATEGORY_SERVE_STALE,
|
||||
NS_LOGCATEGORY_TAT,
|
||||
NS_LOGCATEGORY_UPDATE,
|
||||
NS_LOGCATEGORY_UPDATE_SECURITY,
|
||||
/* cfg categories */
|
||||
CFG_LOGCATEGORY_CONFIG,
|
||||
/* named categories */
|
||||
|
||||
+21
-20
@@ -170,36 +170,37 @@ static const char *categories_description[] = {
|
||||
[ISC_LOGCATEGORY_GENERAL] = "general",
|
||||
[ISC_LOGCATEGORY_SSLKEYLOG] = "sslkeylog",
|
||||
/* dns categories */
|
||||
[DNS_LOGCATEGORY_NOTIFY] = "notify",
|
||||
[DNS_LOGCATEGORY_CNAME] = "cname",
|
||||
[DNS_LOGCATEGORY_DATABASE] = "database",
|
||||
[DNS_LOGCATEGORY_SECURITY] = "security",
|
||||
[DNS_LOGCATEGORY_DISPATCH] = "dispatch",
|
||||
[DNS_LOGCATEGORY_DNSSEC] = "dnssec",
|
||||
[DNS_LOGCATEGORY_DNSTAP] = "dnstap",
|
||||
[DNS_LOGCATEGORY_EDNS_DISABLED] = "edns-disabled",
|
||||
[DNS_LOGCATEGORY_LAME_SERVERS] = "lame-servers",
|
||||
[DNS_LOGCATEGORY_NOTIFY] = "notify",
|
||||
[DNS_LOGCATEGORY_NSID] = "nsid",
|
||||
[DNS_LOGCATEGORY_RESOLVER] = "resolver",
|
||||
[DNS_LOGCATEGORY_RPZ] = "rpz",
|
||||
[DNS_LOGCATEGORY_RPZ_PASSTHRU] = "rpz-passthru",
|
||||
[DNS_LOGCATEGORY_RRL] = "rate-limit",
|
||||
[DNS_LOGCATEGORY_SECURITY] = "security",
|
||||
[DNS_LOGCATEGORY_SPILL] = "spill",
|
||||
[DNS_LOGCATEGORY_UPDATE_POLICY] = "update-policy",
|
||||
[DNS_LOGCATEGORY_XFER_IN] = "xfer-in",
|
||||
[DNS_LOGCATEGORY_XFER_OUT] = "xfer-out",
|
||||
[DNS_LOGCATEGORY_DISPATCH] = "dispatch",
|
||||
[DNS_LOGCATEGORY_LAME_SERVERS] = "lame-servers",
|
||||
[DNS_LOGCATEGORY_EDNS_DISABLED] = "edns-disabled",
|
||||
[DNS_LOGCATEGORY_RPZ] = "rpz",
|
||||
[DNS_LOGCATEGORY_RRL] = "rate-limit",
|
||||
[DNS_LOGCATEGORY_CNAME] = "cname",
|
||||
[DNS_LOGCATEGORY_SPILL] = "spill",
|
||||
[DNS_LOGCATEGORY_DNSTAP] = "dnstap",
|
||||
[DNS_LOGCATEGORY_ZONELOAD] = "zoneload",
|
||||
[DNS_LOGCATEGORY_NSID] = "nsid",
|
||||
[DNS_LOGCATEGORY_RPZ_PASSTHRU] = "rpz-passthru",
|
||||
[DNS_LOGCATEGORY_UPDATE_POLICY] = "update-policy",
|
||||
[DNS_LOGCATEGORY_ZONEVERSION] = "zoneversion",
|
||||
/* ns categories */
|
||||
[NS_LOGCATEGORY_CLIENT] = "client",
|
||||
[NS_LOGCATEGORY_NETWORK] = "network",
|
||||
[NS_LOGCATEGORY_UPDATE] = "update",
|
||||
[NS_LOGCATEGORY_QUERIES] = "queries",
|
||||
[NS_LOGCATEGORY_UPDATE_SECURITY] = "update-security",
|
||||
[NS_LOGCATEGORY_QUERY_ERRORS] = "query-errors",
|
||||
[NS_LOGCATEGORY_TAT] = "trust-anchor-telemetry",
|
||||
[NS_LOGCATEGORY_DRA] = "dns-reporting-agent",
|
||||
[NS_LOGCATEGORY_SERVE_STALE] = "serve-stale",
|
||||
[NS_LOGCATEGORY_NETWORK] = "network",
|
||||
[NS_LOGCATEGORY_QUERIES] = "queries",
|
||||
[NS_LOGCATEGORY_QUERY_ERRORS] = "query-errors",
|
||||
[NS_LOGCATEGORY_RESPONSES] = "responses",
|
||||
[NS_LOGCATEGORY_SERVE_STALE] = "serve-stale",
|
||||
[NS_LOGCATEGORY_TAT] = "trust-anchor-telemetry",
|
||||
[NS_LOGCATEGORY_UPDATE] = "update",
|
||||
[NS_LOGCATEGORY_UPDATE_SECURITY] = "update-security",
|
||||
/* cfg categories */
|
||||
[CFG_LOGCATEGORY_CONFIG] = "config",
|
||||
/* named categories */
|
||||
|
||||
+9
-11
@@ -16,6 +16,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/ascii.h>
|
||||
#include <isc/fxhash.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/hashmap.h>
|
||||
#include <isc/magic.h>
|
||||
@@ -31,9 +32,9 @@ typedef struct elt {
|
||||
isc_symvalue_t value;
|
||||
} elt_t;
|
||||
|
||||
/* 7 bits means 128 entries at creation, which matches the common use of
|
||||
/* 4 bits means 16 entries at creation, which matches the common use of
|
||||
* symtab */
|
||||
#define ISC_SYMTAB_INIT_HASH_BITS 7
|
||||
#define ISC_SYMTAB_INIT_HASH_BITS 4
|
||||
#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
|
||||
#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
|
||||
|
||||
@@ -122,7 +123,7 @@ elt__match(void *node, const void *key0, bool case_sensitive) {
|
||||
if (case_sensitive) {
|
||||
return memcmp(elt->key, key->key, key->size) == 0;
|
||||
} else {
|
||||
return isc_ascii_lowercmp(elt->key, key->key, key->size) == 0;
|
||||
return isc_ascii_lowerequal(elt->key, key->key, key->size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,14 +137,11 @@ elt_match_nocase(void *node, const void *key) {
|
||||
return elt__match(node, key, false);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
elt_hash(elt_t *elt, bool case_sensitive) {
|
||||
isc_hash32_t hash;
|
||||
|
||||
isc_hash32_init(&hash);
|
||||
isc_hash32_hash(&hash, elt->key, elt->size, case_sensitive);
|
||||
isc_hash32_hash(&hash, &elt->type, sizeof(elt->type), false);
|
||||
return isc_hash32_finalize(&hash);
|
||||
static inline uint32_t
|
||||
elt_hash(elt_t *restrict elt, bool case_sensitive) {
|
||||
const uint8_t *ptr = elt->key;
|
||||
size_t len = elt->size;
|
||||
return fx_hash_bytes(0, ptr, len, case_sensitive);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
||||
@@ -4242,6 +4242,7 @@ static struct {
|
||||
{ "request-expire", dns_peer_setrequestexpire },
|
||||
{ "request-ixfr", dns_peer_setrequestixfr },
|
||||
{ "request-nsid", dns_peer_setrequestnsid },
|
||||
{ "request-zoneversion", dns_peer_setrequestzoneversion },
|
||||
{ "send-cookie", dns_peer_setsendcookie },
|
||||
{ "tcp-keepalive", dns_peer_settcpkeepalive },
|
||||
{ "tcp-only", dns_peer_setforcetcp },
|
||||
|
||||
@@ -2110,6 +2110,7 @@ static cfg_clausedef_t view_clauses[] = {
|
||||
{ "recursion", &cfg_type_boolean, 0 },
|
||||
{ "request-nsid", &cfg_type_boolean, 0 },
|
||||
{ "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "request-zoneversion", &cfg_type_boolean, 0 },
|
||||
{ "require-server-cookie", &cfg_type_boolean, 0 },
|
||||
{ "resolver-nonbackoff-tries", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "resolver-query-timeout", &cfg_type_uint32, 0 },
|
||||
@@ -2354,6 +2355,8 @@ static cfg_clausedef_t zone_clauses[] = {
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
|
||||
{ "parental-source-v6", &cfg_type_sockaddr6wild,
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
|
||||
{ "provide-zoneversion", &cfg_type_boolean,
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
|
||||
{ "send-report-channel", &cfg_type_astring,
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
|
||||
{ "request-expire", &cfg_type_boolean,
|
||||
@@ -2603,6 +2606,7 @@ static cfg_clausedef_t server_clauses[] = {
|
||||
{ "request-ixfr", &cfg_type_boolean, 0 },
|
||||
{ "request-ixfr-max-diffs", &cfg_type_uint32, 0 },
|
||||
{ "request-nsid", &cfg_type_boolean, 0 },
|
||||
{ "request-zoneversion", &cfg_type_boolean, 0 },
|
||||
{ "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "require-cookie", &cfg_type_boolean, 0 },
|
||||
{ "send-cookie", &cfg_type_boolean, 0 },
|
||||
|
||||
+60
-5
@@ -102,6 +102,8 @@
|
||||
#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0)
|
||||
#define WANTPAD(x) (((x)->attributes & NS_CLIENTATTR_WANTPAD) != 0)
|
||||
#define WANTRC(x) (((x)->attributes & NS_CLIENTATTR_WANTRC) != 0)
|
||||
#define WANTZONEVERSION(x) \
|
||||
(((x)->attributes & NS_CLIENTATTR_WANTZONEVERSION) != 0)
|
||||
|
||||
#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
|
||||
#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC)
|
||||
@@ -218,6 +220,17 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
|
||||
/* XXXWPK TODO use netmgr to set timeout */
|
||||
}
|
||||
|
||||
static void
|
||||
client_zoneversion_reset(ns_client_t *client) {
|
||||
if (client->zoneversion == NULL) {
|
||||
return;
|
||||
}
|
||||
isc_mem_put(client->manager->mctx, client->zoneversion,
|
||||
client->zoneversionlength);
|
||||
client->zoneversion = NULL;
|
||||
client->zoneversionlength = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ns_client_endrequest(ns_client_t *client) {
|
||||
INSIST(client->state == NS_CLIENTSTATE_WORKING ||
|
||||
@@ -258,6 +271,7 @@ ns_client_endrequest(ns_client_t *client) {
|
||||
dns_message_puttemprdataset(client->message, &client->opt);
|
||||
}
|
||||
|
||||
client_zoneversion_reset(client);
|
||||
client->signer = NULL;
|
||||
client->udpsize = 512;
|
||||
client->extflags = 0;
|
||||
@@ -1192,6 +1206,13 @@ no_nsid:
|
||||
ednsopts[count].value = ede->value;
|
||||
count++;
|
||||
}
|
||||
if ((client->attributes & NS_CLIENTATTR_HAVEZONEVERSION) != 0) {
|
||||
INSIST(count < DNS_EDNSOPTIONS);
|
||||
ednsopts[count].code = DNS_OPT_ZONEVERSION;
|
||||
ednsopts[count].length = client->zoneversionlength;
|
||||
ednsopts[count].value = client->zoneversion;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (WANTRC(client)) {
|
||||
dns_name_t *rad = NULL;
|
||||
@@ -1290,6 +1311,7 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
||||
isc_stdtime_t now;
|
||||
uint32_t when;
|
||||
isc_buffer_t db;
|
||||
bool alwaysvalid;
|
||||
|
||||
/*
|
||||
* If we have already seen a cookie option skip this cookie option.
|
||||
@@ -1335,11 +1357,22 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
||||
when = isc_buffer_getuint32(buf);
|
||||
isc_buffer_forward(buf, 8);
|
||||
|
||||
/*
|
||||
* For '-T cookiealwaysvalid' still process everything to not skew any
|
||||
* performance tests involving cookies, but make sure that the cookie
|
||||
* check passes in the end, given the cookie was structurally correct.
|
||||
*/
|
||||
alwaysvalid = ns_server_getoption(client->manager->sctx,
|
||||
NS_SERVER_COOKIEALWAYSVALID);
|
||||
|
||||
/*
|
||||
* Allow for a 5 minute clock skew between servers sharing a secret.
|
||||
* Only accept COOKIE if we have talked to the client in the last hour.
|
||||
*/
|
||||
now = isc_stdtime_now();
|
||||
if (alwaysvalid) {
|
||||
now = when;
|
||||
}
|
||||
if (isc_serial_gt(when, (now + 300)) /* In the future. */ ||
|
||||
isc_serial_lt(when, (now - 3600)) /* In the past. */)
|
||||
{
|
||||
@@ -1352,7 +1385,7 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
||||
isc_buffer_init(&db, dbuf, sizeof(dbuf));
|
||||
compute_cookie(client, when, client->manager->sctx->secret, &db);
|
||||
|
||||
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE)) {
|
||||
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE) || alwaysvalid) {
|
||||
ns_stats_increment(client->manager->sctx->nsstats,
|
||||
ns_statscounter_cookiematch);
|
||||
client->attributes |= NS_CLIENTATTR_HAVECOOKIE;
|
||||
@@ -1597,8 +1630,7 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
||||
case DNS_OPT_CLIENT_SUBNET:
|
||||
result = process_ecs(client, &optbuf, optlen);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_error(client, result);
|
||||
return result;
|
||||
goto formerr;
|
||||
}
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
@@ -1626,13 +1658,24 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
||||
result = process_keytag(client, &optbuf,
|
||||
optlen);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_error(client, result);
|
||||
return result;
|
||||
goto formerr;
|
||||
}
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
ns_statscounter_keytagopt);
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (optlen != 0 || WANTZONEVERSION(client)) {
|
||||
result = DNS_R_FORMERR;
|
||||
goto formerr;
|
||||
}
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
ns_statscounter_zoneversionopt);
|
||||
client->attributes |=
|
||||
NS_CLIENTATTR_WANTZONEVERSION;
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
break;
|
||||
default:
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
@@ -1648,6 +1691,17 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
||||
client->attributes |= NS_CLIENTATTR_WANTOPT;
|
||||
|
||||
return result;
|
||||
|
||||
formerr:
|
||||
if (result == DNS_R_FORMERR || result == DNS_R_OPTERR) {
|
||||
result = ns_client_addopt(client, client->message,
|
||||
&client->opt);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = DNS_R_FORMERR;
|
||||
}
|
||||
}
|
||||
ns_client_error(client, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1712,6 +1766,7 @@ ns__client_put_cb(void *client0) {
|
||||
*/
|
||||
ns_query_free(client);
|
||||
dns_ede_invalidate(&client->edectx);
|
||||
client_zoneversion_reset(client);
|
||||
|
||||
client->magic = 0;
|
||||
|
||||
|
||||
+23
-19
@@ -224,6 +224,8 @@ struct ns_client {
|
||||
ISC_LINK(ns_client_t) rlink;
|
||||
unsigned char cookie[8];
|
||||
uint32_t expire;
|
||||
unsigned char *zoneversion;
|
||||
uint32_t zoneversionlength;
|
||||
unsigned char *keytag;
|
||||
uint16_t keytag_len;
|
||||
|
||||
@@ -241,26 +243,28 @@ struct ns_client {
|
||||
#define NS_CLIENT_MAGIC ISC_MAGIC('N', 'S', 'C', 'c')
|
||||
#define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC)
|
||||
|
||||
#define NS_CLIENTATTR_TCP 0x00001
|
||||
#define NS_CLIENTATTR_RA 0x00002 /*%< Client gets recursive service */
|
||||
#define NS_CLIENTATTR_PKTINFO 0x00004 /*%< pktinfo is valid */
|
||||
#define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */
|
||||
#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
|
||||
#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
|
||||
#define NS_CLIENTATTR_TCP 0x000001
|
||||
#define NS_CLIENTATTR_RA 0x000002 /*%< Client gets recursive service */
|
||||
#define NS_CLIENTATTR_PKTINFO 0x000004 /*%< pktinfo is valid */
|
||||
#define NS_CLIENTATTR_MULTICAST 0x000008 /*%< recv'd from multicast */
|
||||
#define NS_CLIENTATTR_WANTDNSSEC 0x000010 /*%< include dnssec records */
|
||||
#define NS_CLIENTATTR_WANTNSID 0x000020 /*%< include nameserver ID */
|
||||
#define NS_CLIENTATTR_BADCOOKIE \
|
||||
0x00040 /*%< Presented cookie is bad/out-of-date */
|
||||
#define NS_CLIENTATTR_WANTRC 0x00080 /*%< include Report-Channel */
|
||||
#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
|
||||
#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
|
||||
#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
|
||||
#define NS_CLIENTATTR_WANTEXPIRE 0x00800 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_HAVEEXPIRE 0x01000 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_WANTOPT 0x02000 /*%< add opt to reply */
|
||||
#define NS_CLIENTATTR_HAVEECS 0x04000 /*%< received an ECS option */
|
||||
#define NS_CLIENTATTR_WANTPAD 0x08000 /*%< pad reply */
|
||||
#define NS_CLIENTATTR_USEKEEPALIVE 0x10000 /*%< use TCP keepalive */
|
||||
#define NS_CLIENTATTR_NOSETFC 0x20000 /*%< don't set servfail cache */
|
||||
#define NS_CLIENTATTR_NEEDTCP 0x40000 /*%< send TC=1 */
|
||||
0x000040 /*%< Presented cookie is bad/out-of-date */
|
||||
#define NS_CLIENTATTR_WANTRC 0x000080 /*%< include Report-Channel */
|
||||
#define NS_CLIENTATTR_WANTAD 0x000100 /*%< want AD in response if possible */
|
||||
#define NS_CLIENTATTR_WANTCOOKIE 0x000200 /*%< return a COOKIE */
|
||||
#define NS_CLIENTATTR_HAVECOOKIE 0x000400 /*%< has a valid COOKIE */
|
||||
#define NS_CLIENTATTR_WANTEXPIRE 0x000800 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_HAVEEXPIRE 0x001000 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_WANTOPT 0x002000 /*%< add opt to reply */
|
||||
#define NS_CLIENTATTR_HAVEECS 0x004000 /*%< received an ECS option */
|
||||
#define NS_CLIENTATTR_WANTPAD 0x008000 /*%< pad reply */
|
||||
#define NS_CLIENTATTR_USEKEEPALIVE 0x010000 /*%< use TCP keepalive */
|
||||
#define NS_CLIENTATTR_NOSETFC 0x020000 /*%< don't set servfail cache */
|
||||
#define NS_CLIENTATTR_NEEDTCP 0x040000 /*%< send TC=1 */
|
||||
#define NS_CLIENTATTR_WANTZONEVERSION 0x100000 /*%< return zoneversion */
|
||||
#define NS_CLIENTATTR_HAVEZONEVERSION 0x200000 /*%< return zoneversion */
|
||||
|
||||
/*
|
||||
* Flag to use with the SERVFAIL cache to indicate
|
||||
|
||||
+19
-18
@@ -32,24 +32,25 @@
|
||||
|
||||
#include <ns/types.h>
|
||||
|
||||
#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */
|
||||
#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */
|
||||
#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */
|
||||
#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */
|
||||
#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */
|
||||
#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */
|
||||
#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */
|
||||
#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */
|
||||
#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */
|
||||
#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */
|
||||
#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */
|
||||
#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */
|
||||
#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */
|
||||
#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */
|
||||
#define NS_SERVER_TRANSFERINSECS 0x00008000U /*%< -T transferinsecs */
|
||||
#define NS_SERVER_TRANSFERSLOWLY 0x00010000U /*%< -T transferslowly */
|
||||
#define NS_SERVER_TRANSFERSTUCK 0x00020000U /*%< -T transferstuck */
|
||||
#define NS_SERVER_LOGRESPONSES 0x00040000U /*%< log responses */
|
||||
#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */
|
||||
#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */
|
||||
#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */
|
||||
#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */
|
||||
#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */
|
||||
#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */
|
||||
#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */
|
||||
#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */
|
||||
#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */
|
||||
#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */
|
||||
#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */
|
||||
#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */
|
||||
#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */
|
||||
#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */
|
||||
#define NS_SERVER_TRANSFERINSECS 0x00008000U /*%< -T transferinsecs */
|
||||
#define NS_SERVER_TRANSFERSLOWLY 0x00010000U /*%< -T transferslowly */
|
||||
#define NS_SERVER_TRANSFERSTUCK 0x00020000U /*%< -T transferstuck */
|
||||
#define NS_SERVER_LOGRESPONSES 0x00040000U /*%< log responses */
|
||||
#define NS_SERVER_COOKIEALWAYSVALID 0x00080000U /*%< -T cookiealwaysvalid */
|
||||
|
||||
/*%
|
||||
* Type for callback function to get hostname.
|
||||
|
||||
+32
-31
@@ -84,49 +84,50 @@ enum {
|
||||
ns_statscounter_ecsopt = 46,
|
||||
ns_statscounter_padopt = 47,
|
||||
ns_statscounter_keepaliveopt = 48,
|
||||
ns_statscounter_zoneversionopt = 49,
|
||||
|
||||
ns_statscounter_nxdomainredirect = 49,
|
||||
ns_statscounter_nxdomainredirect_rlookup = 50,
|
||||
ns_statscounter_nxdomainredirect = 50,
|
||||
ns_statscounter_nxdomainredirect_rlookup = 51,
|
||||
|
||||
ns_statscounter_cookiein = 51,
|
||||
ns_statscounter_cookiebadsize = 52,
|
||||
ns_statscounter_cookiebadtime = 53,
|
||||
ns_statscounter_cookienomatch = 54,
|
||||
ns_statscounter_cookiematch = 55,
|
||||
ns_statscounter_cookienew = 56,
|
||||
ns_statscounter_badcookie = 57,
|
||||
ns_statscounter_cookiein = 52,
|
||||
ns_statscounter_cookiebadsize = 53,
|
||||
ns_statscounter_cookiebadtime = 54,
|
||||
ns_statscounter_cookienomatch = 55,
|
||||
ns_statscounter_cookiematch = 56,
|
||||
ns_statscounter_cookienew = 57,
|
||||
ns_statscounter_badcookie = 58,
|
||||
|
||||
ns_statscounter_nxdomainsynth = 58,
|
||||
ns_statscounter_nodatasynth = 59,
|
||||
ns_statscounter_wildcardsynth = 60,
|
||||
ns_statscounter_nxdomainsynth = 59,
|
||||
ns_statscounter_nodatasynth = 60,
|
||||
ns_statscounter_wildcardsynth = 61,
|
||||
|
||||
ns_statscounter_trystale = 61,
|
||||
ns_statscounter_usedstale = 62,
|
||||
ns_statscounter_trystale = 62,
|
||||
ns_statscounter_usedstale = 63,
|
||||
|
||||
ns_statscounter_prefetch = 63,
|
||||
ns_statscounter_keytagopt = 64,
|
||||
ns_statscounter_prefetch = 64,
|
||||
ns_statscounter_keytagopt = 65,
|
||||
|
||||
ns_statscounter_tcphighwater = 65,
|
||||
ns_statscounter_tcphighwater = 66,
|
||||
|
||||
ns_statscounter_reclimitdropped = 66,
|
||||
ns_statscounter_reclimitdropped = 67,
|
||||
|
||||
ns_statscounter_updatequota = 67,
|
||||
ns_statscounter_updatequota = 68,
|
||||
|
||||
ns_statscounter_recurshighwater = 68,
|
||||
ns_statscounter_recurshighwater = 69,
|
||||
|
||||
ns_statscounter_dot = 69,
|
||||
ns_statscounter_doh = 70,
|
||||
ns_statscounter_dohplain = 71,
|
||||
ns_statscounter_dot = 70,
|
||||
ns_statscounter_doh = 71,
|
||||
ns_statscounter_dohplain = 72,
|
||||
|
||||
ns_statscounter_proxyudp = 72,
|
||||
ns_statscounter_proxytcp = 73,
|
||||
ns_statscounter_proxydot = 74,
|
||||
ns_statscounter_proxydoh = 75,
|
||||
ns_statscounter_proxydohplain = 76,
|
||||
ns_statscounter_encryptedproxydot = 77,
|
||||
ns_statscounter_encryptedproxydoh = 78,
|
||||
ns_statscounter_proxyudp = 73,
|
||||
ns_statscounter_proxytcp = 74,
|
||||
ns_statscounter_proxydot = 75,
|
||||
ns_statscounter_proxydoh = 76,
|
||||
ns_statscounter_proxydohplain = 77,
|
||||
ns_statscounter_encryptedproxydot = 78,
|
||||
ns_statscounter_encryptedproxydoh = 79,
|
||||
|
||||
ns_statscounter_max = 79,
|
||||
ns_statscounter_max = 80,
|
||||
};
|
||||
|
||||
void
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user