mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-27 20:25:55 -04:00
Merge tag 'v9.20.23' into bind-9.20
This commit is contained in:
commit
3d293e2a1e
77 changed files with 3076 additions and 406 deletions
|
|
@ -123,6 +123,7 @@ extern unsigned int dns_zone_mkey_month;
|
|||
extern unsigned int dns_adb_entrywindow;
|
||||
extern unsigned int dns_adb_cachemin;
|
||||
extern size_t dns_dispatch_tcppipelining;
|
||||
extern size_t dns_adb_addrslimit;
|
||||
|
||||
static bool want_stats = false;
|
||||
static char program_name[NAME_MAX] = "named";
|
||||
|
|
@ -817,6 +818,13 @@ parse_T_opt(char *option) {
|
|||
"least 1");
|
||||
}
|
||||
dns_dispatch_tcppipelining = pipelining;
|
||||
} else if (!strncmp(option, "adbaddrslimit=", 14)) {
|
||||
size_t adb_addrslimit = atoi(option + 14);
|
||||
if (adb_addrslimit < 1) {
|
||||
named_main_earlyfatal("adbaddrslimit must be at "
|
||||
"least 1");
|
||||
}
|
||||
dns_adb_addrslimit = adb_addrslimit;
|
||||
} else {
|
||||
fprintf(stderr, "unknown -T flag '%s'\n", option);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1917,10 +1917,12 @@ dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
|
|||
dns_rdataclass_t zclass = view->rdclass;
|
||||
isc_result_t result;
|
||||
|
||||
dns_zone_setclass(zone, zclass);
|
||||
result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dns_zone_setstats(zone, named_g_server->zonestats);
|
||||
|
||||
return named_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin);
|
||||
|
|
@ -4428,7 +4430,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
obj = NULL;
|
||||
result = named_config_get(maps, "recursion", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->recursion = cfg_obj_asboolean(obj);
|
||||
view->recursion = (view->rdclass == dns_rdataclass_in &&
|
||||
cfg_obj_asboolean(obj));
|
||||
|
||||
if (named_g_maxcachesize != 0) {
|
||||
/*
|
||||
|
|
@ -5144,35 +5147,15 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
}
|
||||
|
||||
/*
|
||||
* We have default hints for class IN if we need them.
|
||||
* We have default root hints for class IN if we need them.
|
||||
* Each view gets its own rootdb so a priming response only
|
||||
* writes into that view's copy. Other classes don't support
|
||||
* recursion and don't need hints.
|
||||
*/
|
||||
if (view->rdclass == dns_rdataclass_in && view->hints == NULL) {
|
||||
dns_view_sethints(view, named_g_server->in_roothints);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we still have no hints, this is a non-IN view with no
|
||||
* "hints zone" configured. Issue a warning, except if this
|
||||
* is a root server. Root servers never need to consult
|
||||
* their hints, so it's no point requiring users to configure
|
||||
* them.
|
||||
*/
|
||||
if (view->hints == NULL) {
|
||||
dns_zone_t *rootzone = NULL;
|
||||
(void)dns_view_findzone(view, dns_rootname, DNS_ZTFIND_EXACT,
|
||||
&rootzone);
|
||||
if (rootzone != NULL) {
|
||||
dns_zone_detach(&rootzone);
|
||||
need_hints = false;
|
||||
}
|
||||
if (need_hints) {
|
||||
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
|
||||
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
|
||||
"no root hints for view '%s'",
|
||||
view->name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the view's transports (DoT/DoH)
|
||||
*/
|
||||
|
|
@ -5408,14 +5391,13 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
"allow-proxy-on", NULL, actx, named_g_mctx,
|
||||
&view->proxyonacl));
|
||||
|
||||
if (strcmp(view->name, "_bind") != 0 &&
|
||||
view->rdclass != dns_rdataclass_chaos)
|
||||
{
|
||||
/* named.conf only */
|
||||
if (view->rdclass != dns_rdataclass_in) {
|
||||
dns_acl_none(named_g_mctx, &view->recursionacl);
|
||||
dns_acl_none(named_g_mctx, &view->recursiononacl);
|
||||
} else {
|
||||
CHECK(configure_view_acl(vconfig, config, NULL,
|
||||
"allow-recursion", NULL, actx,
|
||||
named_g_mctx, &view->recursionacl));
|
||||
/* named.conf only */
|
||||
CHECK(configure_view_acl(vconfig, config, NULL,
|
||||
"allow-recursion-on", NULL, actx,
|
||||
named_g_mctx, &view->recursiononacl));
|
||||
|
|
|
|||
|
|
@ -703,7 +703,7 @@ $DIG -p ${PORT} @10.53.1.2 d.normal.example a >dig.out.ns3.4.$n || ret=1
|
|||
grep 'recursion requested but not available' dig.out.ns3.4.$n >/dev/null || ret=1
|
||||
grep 'status: REFUSED' dig.out.ns3.4.$n >/dev/null || ret=1
|
||||
grep 'EDE: 18 (Prohibited)' dig.out.ns3.4.$n >/dev/null || ret=1
|
||||
nextpart ns3/named.run | grep 'allow-recursion-on did not match' >/dev/null || ret=1
|
||||
nextpart ns3/named.run | grep 'allow-query-cache-on did not match' >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
|
|
|||
|
|
@ -545,6 +545,7 @@ $CHECKCONF -l good.conf \
|
|||
| grep -v "is not implemented" \
|
||||
| grep -v "is not recommended" \
|
||||
| grep -v "no longer exists" \
|
||||
| grep -v "recursion will be disabled" \
|
||||
| grep -v "is obsolete" >checkconf.out$n || ret=1
|
||||
diff good.zonelist checkconf.out$n >diff.out$n || ret=1
|
||||
if [ $ret -ne 0 ]; then
|
||||
|
|
@ -805,5 +806,16 @@ if [ $ret != 0 ]; then
|
|||
fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check 'recursion yes;' is warned and disabled in a non-IN view ($n)"
|
||||
ret=0
|
||||
$CHECKCONF warn-chaos-recursion.conf >checkconf.out$n 2>&1 || ret=1
|
||||
grep -F "recursion will be disabled" checkconf.out$n >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then
|
||||
echo_i "failed"
|
||||
ret=1
|
||||
fi
|
||||
status=$((status + ret))
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
|
|
|||
12
bin/tests/system/checkconf/warn-chaos-recursion.conf
Normal file
12
bin/tests/system/checkconf/warn-chaos-recursion.conf
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
options {
|
||||
directory ".";
|
||||
};
|
||||
|
||||
view chaos ch {
|
||||
match-clients { any; };
|
||||
recursion yes;
|
||||
zone "." {
|
||||
type hint;
|
||||
file "chaos.hints";
|
||||
};
|
||||
};
|
||||
4
bin/tests/system/class/ns1/chaos.db.in
Normal file
4
bin/tests/system/class/ns1/chaos.db.in
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
. CH NS ns.root.
|
||||
ns.root. CH A ns.root. 1
|
||||
ns.root. CH AAAA \# 1 00
|
||||
|
||||
31
bin/tests/system/class/ns1/named.conf.j2
Normal file
31
bin/tests/system/class/ns1/named.conf.j2
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
listen-on-v6 { none; };
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
view chaos ch {
|
||||
match-clients { any; };
|
||||
recursion yes;
|
||||
zone "." {
|
||||
type hint;
|
||||
file "chaos.db";
|
||||
};
|
||||
zone "version.bind" {
|
||||
type primary;
|
||||
database "_builtin version";
|
||||
};
|
||||
};
|
||||
6
bin/tests/system/class/ns2/example.db.in
Normal file
6
bin/tests/system/class/ns2/example.db.in
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
$TTL 300
|
||||
@ CH SOA ns.example. hostmaster.example. 1 3600 1200 604800 300
|
||||
@ CH NS ns.example.
|
||||
ns CH TXT "ns"
|
||||
a CH A target.example. 1
|
||||
target CH TXT "target"
|
||||
11
bin/tests/system/class/ns2/localhost.db.in
Normal file
11
bin/tests/system/class/ns2/localhost.db.in
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
$ORIGIN 1.0.0.127.in-addr.arpa.
|
||||
$TTL 300
|
||||
@ IN SOA ns hostmaster 1 3600 900 604800 300
|
||||
@ IN NS ns
|
||||
ns IN A 127.0.0.1
|
||||
|
||||
@ IN KX 10 target.example.
|
||||
@ IN PX 10 map822.example. mapx400.example.
|
||||
@ IN NSAP 0x47000580ffff0000000001e133ffffff00016200
|
||||
@ IN NSAP-PTR target.example.
|
||||
@ in EID \# 01 aa
|
||||
42
bin/tests/system/class/ns2/named.conf.j2
Normal file
42
bin/tests/system/class/ns2/named.conf.j2
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
options {
|
||||
directory ".";
|
||||
query-source address 10.53.0.2;
|
||||
notify-source 10.53.0.2;
|
||||
transfer-source 10.53.0.2;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.2; };
|
||||
listen-on-v6 { none; };
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
view default {
|
||||
match-clients { any; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
zone "1.0.0.127.in-addr.arpa." {
|
||||
type primary;
|
||||
file "localhost.db";
|
||||
update-policy {
|
||||
grant * tcp-self . ANY;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
view chaos ch {
|
||||
match-clients { any; };
|
||||
recursion no;
|
||||
zone example {
|
||||
type primary;
|
||||
file "example.db";
|
||||
allow-update { any; };
|
||||
};
|
||||
};
|
||||
28
bin/tests/system/class/ns3/named.conf.j2
Normal file
28
bin/tests/system/class/ns3/named.conf.j2
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
options {
|
||||
directory ".";
|
||||
query-source address 10.53.0.3;
|
||||
notify-source 10.53.0.3;
|
||||
transfer-source 10.53.0.3;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
listen-on-v6 { none; };
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
view chaos ch {
|
||||
match-clients { any; };
|
||||
recursion yes;
|
||||
dnssec-validation no;
|
||||
forward only;
|
||||
forwarders port @PORT@ { 10.53.0.2; };
|
||||
deny-answer-addresses { 0.0.0.0/0; ::/0; };
|
||||
};
|
||||
19
bin/tests/system/class/setup.sh
Normal file
19
bin/tests/system/class/setup.sh
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# shellcheck source=conf.sh
|
||||
. ../conf.sh
|
||||
|
||||
cp ns1/chaos.db.in ns1/chaos.db
|
||||
cp ns2/example.db.in ns2/example.db
|
||||
cp ns2/localhost.db.in ns2/localhost.db
|
||||
54
bin/tests/system/class/tests_class_chaos.py
Normal file
54
bin/tests/system/class/tests_class_chaos.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
|
||||
import dns.opcode
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"*/*.db",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_chaos_recursion():
|
||||
msg = isctest.query.create("foo.example.", "TXT", qclass="CH")
|
||||
res = isctest.query.udp(msg, "10.53.0.1")
|
||||
isctest.check.refused(res)
|
||||
|
||||
|
||||
def test_chaos_auth():
|
||||
msg = isctest.query.create("a.example.", "A", qclass="CH")
|
||||
res = isctest.query.udp(msg, "10.53.0.2")
|
||||
isctest.check.noerror(res)
|
||||
|
||||
|
||||
def test_chaos_forward():
|
||||
msg = isctest.query.create("a.example.", "A", qclass="CH")
|
||||
res = isctest.query.udp(msg, "10.53.0.3")
|
||||
isctest.check.refused(res)
|
||||
|
||||
|
||||
def test_chaos_notify():
|
||||
msg = isctest.query.create("example.", "SOA", qclass="CH", rd=False, dnssec=False)
|
||||
msg.set_opcode(dns.opcode.NOTIFY)
|
||||
msg.flags = dns.opcode.to_flags(dns.opcode.NOTIFY)
|
||||
res = isctest.query.udp(msg, "10.53.0.2")
|
||||
isctest.check.notimp(res)
|
||||
|
||||
|
||||
def test_query_class_none():
|
||||
msg = isctest.query.create("example.", "A", qclass="NONE")
|
||||
res = isctest.query.udp(msg, "10.53.0.2")
|
||||
isctest.check.formerr(res)
|
||||
137
bin/tests/system/class/tests_class_update.py
Normal file
137
bin/tests/system/class/tests_class_update.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import socket
|
||||
import struct
|
||||
|
||||
from dns import message, rdataclass, rdatatype, update
|
||||
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"*/*.db",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def encode_name(name: str) -> bytes:
|
||||
out = b""
|
||||
for label in name.rstrip(".").split("."):
|
||||
out += bytes([len(label)]) + label.encode("ascii")
|
||||
return out + b"\x00"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"rdtype,rdclass,ttl,rdata",
|
||||
[
|
||||
(rdatatype.SRV, rdataclass.NONE, 0, b"\x00\x00\x00\x00\x00\x00\x01"),
|
||||
(rdatatype.SRV, rdataclass.NONE, 0, b"\x00"),
|
||||
(rdatatype.KX, rdataclass.NONE, 0, b""),
|
||||
(rdatatype.PX, rdataclass.NONE, 0, b""),
|
||||
(rdatatype.NSAP, rdataclass.NONE, 0, b""),
|
||||
(rdatatype.NSAP_PTR, rdataclass.NONE, 0, b""),
|
||||
(31, rdataclass.NONE, 0, b""), # dnspython doesn't define type EID
|
||||
],
|
||||
)
|
||||
def test_class_invalid(rdtype, rdclass, ttl, rdata, named_port):
|
||||
# these update messages are badly formatted, so we construct
|
||||
# them manually instead of using dnspython.
|
||||
|
||||
# opcode=UPDATE, 1 RRset in ZONE, 1 RRset in UPDATE
|
||||
header = struct.pack("!HHHHHH", 0, 0x2800, 1, 0, 1, 0)
|
||||
|
||||
# ZONE section: QNAME=<zone>, QTYPE=SOA, QCLASS=ANY
|
||||
zone_q = encode_name("1.0.0.127.in-addr.arpa") + struct.pack("!HH", 6, 255)
|
||||
|
||||
# UPDATE section RR:
|
||||
update_rr = (
|
||||
encode_name("1.0.0.127.in-addr.arpa")
|
||||
+ struct.pack("!HHIH", rdtype, rdclass, ttl, len(rdata))
|
||||
+ rdata
|
||||
)
|
||||
|
||||
m = header + zone_q + update_rr
|
||||
packet = struct.pack("!H", len(m)) + m
|
||||
|
||||
with socket.create_connection(
|
||||
("10.53.0.2", named_port), source_address=("127.0.0.1", 0), timeout=2.0
|
||||
) as s:
|
||||
s.sendall(packet)
|
||||
try:
|
||||
rwire = s.recv(4096)
|
||||
res = message.from_wire(rwire)
|
||||
isctest.check.formerr(res)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
|
||||
# check the server is answering
|
||||
msg = isctest.query.create("1.0.0.127.in-addr.arpa", "SRV")
|
||||
res = isctest.query.udp(msg, "10.53.0.2")
|
||||
isctest.check.noerror(res)
|
||||
isctest.check.rr_count_eq(res.answer, 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"rdtype,rdata",
|
||||
[
|
||||
(rdatatype.SVCB, "\\# 02 0000"),
|
||||
(rdatatype.WKS, "\\# 02 4142"),
|
||||
(rdatatype.WKS, "\\# 02 4344"),
|
||||
],
|
||||
)
|
||||
def test_class_chaosupdate(rdtype, rdata):
|
||||
up = update.UpdateMessage("example.", rdclass=rdataclass.CHAOS)
|
||||
up.add("foo.example.", 300, rdtype, rdata)
|
||||
res = isctest.query.tcp(up, "10.53.0.2")
|
||||
isctest.check.notimp(res)
|
||||
|
||||
|
||||
def test_class_undefined(ns2):
|
||||
up = update.UpdateMessage(".", rdclass=257)
|
||||
up.present(".", 0)
|
||||
up.answer[0].rdclass = rdataclass.NONE
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
res = isctest.query.tcp(up, "10.53.0.2")
|
||||
isctest.check.notimp(res)
|
||||
watcher.wait_for_line("invalid message class: CLASS257")
|
||||
|
||||
|
||||
def test_class_zero(ns2):
|
||||
up = update.UpdateMessage(".", rdclass=0)
|
||||
up.present(".", 0)
|
||||
up.answer[0].rdclass = rdataclass.NONE
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
res = isctest.query.tcp(up, "10.53.0.2")
|
||||
isctest.check.formerr(res)
|
||||
watcher.wait_for_line("message class could not be determined")
|
||||
|
||||
|
||||
def test_class_any(ns2):
|
||||
up = update.UpdateMessage(".", rdclass=rdataclass.ANY)
|
||||
up.present(".", 0)
|
||||
up.answer[0].rdclass = rdataclass.NONE
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
res = isctest.query.tcp(up, "10.53.0.2")
|
||||
isctest.check.formerr(res)
|
||||
watcher.wait_for_line("message parsing failed: FORMERR")
|
||||
|
||||
|
||||
def test_class_none(ns2):
|
||||
up = update.UpdateMessage(".", rdclass=rdataclass.NONE)
|
||||
up.present(".", 0)
|
||||
up.answer[0].rdclass = rdataclass.NONE
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
res = isctest.query.tcp(up, "10.53.0.2")
|
||||
isctest.check.formerr(res)
|
||||
watcher.wait_for_line("message parsing failed: FORMERR")
|
||||
73
bin/tests/system/doth/tests_malicious.py
Normal file
73
bin/tests/system/doth/tests_malicious.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
|
||||
from h2.config import H2Configuration
|
||||
from h2.connection import H2Connection
|
||||
from h2.settings import SettingCodes
|
||||
|
||||
import dns.message
|
||||
|
||||
|
||||
def test_settings_frame_flood(ns1, named_httpsport):
|
||||
msg = dns.message.make_query(".", "SOA")
|
||||
wire = msg.to_wire()
|
||||
|
||||
with socket.create_connection((ns1.ip, named_httpsport), timeout=10) as sock:
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
ctx.set_alpn_protocols(["h2"])
|
||||
|
||||
with ctx.wrap_socket(sock, server_hostname=ns1.ip) as tls:
|
||||
config = H2Configuration(client_side=True, header_encoding="utf-8")
|
||||
conn = H2Connection(config=config)
|
||||
conn.initiate_connection()
|
||||
tls.sendall(conn.data_to_send())
|
||||
|
||||
stream_id = conn.get_next_available_stream_id()
|
||||
conn.send_headers(
|
||||
stream_id,
|
||||
[
|
||||
(":method", "POST"),
|
||||
(":path", "/dns-query"),
|
||||
(":scheme", "https"),
|
||||
(":authority", f"{ns1.ip}:{named_httpsport}"),
|
||||
("content-type", "application/dns-message"),
|
||||
("accept", "application/dns-message"),
|
||||
("content-length", str(len(wire))),
|
||||
],
|
||||
)
|
||||
conn.send_data(stream_id, wire, end_stream=True)
|
||||
tls.sendall(conn.data_to_send())
|
||||
|
||||
for i in range(4096):
|
||||
try:
|
||||
conn.update_settings(
|
||||
{
|
||||
SettingCodes.MAX_CONCURRENT_STREAMS: (i % 100) + 1,
|
||||
SettingCodes.INITIAL_WINDOW_SIZE: i + 1,
|
||||
}
|
||||
)
|
||||
tls.sendall(conn.data_to_send())
|
||||
except Exception: # pylint: disable=broad-except
|
||||
break
|
||||
|
||||
if i % 500 == 0:
|
||||
tls.settimeout(0.05)
|
||||
try:
|
||||
while (data := tls.recv(65535)) != b"":
|
||||
conn.receive_data(data)
|
||||
tls.sendall(conn.data_to_send())
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
|
|
@ -46,6 +46,10 @@ def servfail(message: dns.message.Message) -> None:
|
|||
rcode(message, dns.rcode.SERVFAIL)
|
||||
|
||||
|
||||
def formerr(message: dns.message.Message) -> None:
|
||||
rcode(message, dns.rcode.FORMERR)
|
||||
|
||||
|
||||
def adflag(message: dns.message.Message) -> None:
|
||||
assert (message.flags & dns.flags.AD) != 0, str(message)
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ def create(
|
|||
qtype,
|
||||
qclass=dns.rdataclass.IN,
|
||||
dnssec: bool = True,
|
||||
rd: bool = True,
|
||||
cd: bool = False,
|
||||
ad: bool = True,
|
||||
) -> dns.message.Message:
|
||||
|
|
@ -143,7 +144,9 @@ def create(
|
|||
msg = dns.message.make_query(
|
||||
qname, qtype, qclass, use_edns=True, want_dnssec=dnssec
|
||||
)
|
||||
msg.flags = dns.flags.RD
|
||||
msg.flags = 0
|
||||
if rd:
|
||||
msg.flags = dns.flags.RD
|
||||
if ad:
|
||||
msg.flags |= dns.flags.AD
|
||||
if cd:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ update.nil IN SOA ns1.example.nil. hostmaster.example.nil. (
|
|||
3600 ; minimum (1 hour)
|
||||
)
|
||||
update.nil. NS ns1.update.nil.
|
||||
update.nil. KX 0 .
|
||||
ns1.update.nil. A 10.53.0.2
|
||||
ns2.update.nil. AAAA ::1
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -340,8 +340,10 @@ grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
|
|||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "check that TYPE=0 update is handled ($n)"
|
||||
nextpart ns1/named.run >/dev/null
|
||||
echo "a0e4280000010000000100000000060001c00c000000fe000000000000" \
|
||||
| $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp >/dev/null || ret=1
|
||||
| $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp -b >/dev/null || ret=1
|
||||
wait_for_log 2 "message parsing failed: FORMERR" ns1/named.run || ret=1
|
||||
$DIG $DIGOPTS +tcp version.bind txt ch @10.53.0.1 >dig.out.ns1.$n || ret=1
|
||||
grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
|
||||
[ $ret = 0 ] || {
|
||||
|
|
@ -352,20 +354,10 @@ grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
|
|||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "check that TYPE=0 additional data is handled ($n)"
|
||||
nextpart ns1/named.run >/dev/null
|
||||
echo "a0e4280000010000000000010000060001c00c000000fe000000000000" \
|
||||
| $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp >/dev/null || ret=1
|
||||
$DIG $DIGOPTS +tcp version.bind txt ch @10.53.0.1 >dig.out.ns1.$n || ret=1
|
||||
grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
|
||||
[ $ret = 0 ] || {
|
||||
echo_i "failed"
|
||||
status=1
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
ret=0
|
||||
echo_i "check that update to undefined class is handled ($n)"
|
||||
echo "a0e4280000010001000000000000060101c00c000000fe000000000000" \
|
||||
| $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp >/dev/null || ret=1
|
||||
| $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp -b >/dev/null || ret=1
|
||||
wait_for_log 2 "message parsing failed: FORMERR" ns1/named.run || ret=1
|
||||
$DIG $DIGOPTS +tcp version.bind txt ch @10.53.0.1 >dig.out.ns1.$n || ret=1
|
||||
grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
|
||||
[ $ret = 0 ] || {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
# -p <port>: specify port
|
||||
# -t <protocol>: specify UDP or TCP
|
||||
# -r <num>: send packet <num> times
|
||||
# -b: blocking io
|
||||
# -d: dump response packets
|
||||
#
|
||||
# If not specified, address defaults to 127.0.0.1, port to 53, protocol
|
||||
|
|
@ -51,6 +52,8 @@ use strict;
|
|||
use Getopt::Std;
|
||||
use IO::File;
|
||||
use IO::Socket;
|
||||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
sub usage {
|
||||
print ("Usage: packet.pl [-a address] [-d] [-p port] [-t (tcp|udp)] [-r <repeats>] [file]\n");
|
||||
|
|
@ -61,8 +64,6 @@ my $sock;
|
|||
my $proto;
|
||||
|
||||
sub dumppacket {
|
||||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
my $rin;
|
||||
my $rout;
|
||||
|
|
@ -96,7 +97,7 @@ sub dumppacket {
|
|||
}
|
||||
|
||||
my %options={};
|
||||
getopts("a:dp:t:r:", \%options);
|
||||
getopts("a:bdp:t:r:", \%options);
|
||||
|
||||
my $addr = "127.0.0.1";
|
||||
$addr = $options{a} if defined $options{a};
|
||||
|
|
@ -111,6 +112,8 @@ usage if ($proto !~ /^(udp|tcp)$/);
|
|||
my $repeats = 1;
|
||||
$repeats = $options{r} if defined $options{r};
|
||||
|
||||
my $blocking = defined $options{b} ? 1 : 0;
|
||||
|
||||
my $file = "STDIN";
|
||||
if (@ARGV >= 1) {
|
||||
my $filename = shift @ARGV;
|
||||
|
|
@ -132,8 +135,22 @@ my $len = length $data;
|
|||
my $output = unpack("H*", $data);
|
||||
print ("sending $repeats time(s): $output\n");
|
||||
|
||||
|
||||
if (defined $options{d}) {
|
||||
my $request;
|
||||
if ($Net::DNS::VERSION > 0.68) {
|
||||
$request = new Net::DNS::Packet(\$data, 0);
|
||||
$@ and die $@;
|
||||
} else {
|
||||
my $err;
|
||||
($request, $err) = new Net::DNS::Packet(\$data, 0);
|
||||
$err and die $err;
|
||||
}
|
||||
$request->print;
|
||||
}
|
||||
|
||||
$sock = IO::Socket::INET->new(PeerAddr => $addr, PeerPort => $port,
|
||||
Blocking => 0,
|
||||
Blocking => $blocking,
|
||||
Proto => $proto,) or die "$!";
|
||||
|
||||
STDOUT->autoflush(1);
|
||||
|
|
|
|||
126
bin/tests/system/resend_loop/ans3/ans.py
Normal file
126
bin/tests/system/resend_loop/ans3/ans.py
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
# 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 collections.abc import AsyncGenerator
|
||||
|
||||
import dns.edns
|
||||
import dns.name
|
||||
import dns.rcode
|
||||
import dns.rdatatype
|
||||
import dns.rrset
|
||||
|
||||
from isctest.asyncserver import (
|
||||
AsyncDnsServer,
|
||||
DnsResponseSend,
|
||||
QueryContext,
|
||||
ResponseHandler,
|
||||
)
|
||||
|
||||
|
||||
def _get_cookie(qctx: QueryContext):
|
||||
for o in qctx.query.options:
|
||||
if o.otype == dns.edns.OptionType.COOKIE:
|
||||
cookie = o
|
||||
try:
|
||||
if len(cookie.server) == 0:
|
||||
cookie.server = b"\x11\x22\x33\x44\x55\x66\x77\x88"
|
||||
except AttributeError: # dnspython<2.7.0 compat
|
||||
if len(o.data) == 8:
|
||||
cookie.data *= 2
|
||||
|
||||
return cookie
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class PrimeHandler(ResponseHandler):
|
||||
"""
|
||||
Specifically handle priming query for "." NS (type 2)
|
||||
"""
|
||||
|
||||
def match(self, qctx: QueryContext) -> bool:
|
||||
return len(qctx.qname.labels) == 0 and qctx.qtype == dns.rdatatype.NS
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[DnsResponseSend, None]:
|
||||
|
||||
ns_rrset = dns.rrset.from_text(
|
||||
".", dns.rdatatype.NS, qctx.qclass, "a.root-servers.nil."
|
||||
)
|
||||
a_rrset = dns.rrset.from_text(
|
||||
"a.root-servers.nil.", dns.rdatatype.A, qctx.qclass, "10.53.0.3"
|
||||
)
|
||||
|
||||
response = qctx.prepare_new_response(with_zone_data=False)
|
||||
response.set_rcode(dns.rcode.NOERROR)
|
||||
response.answer.append(ns_rrset)
|
||||
response.additional.append(a_rrset)
|
||||
|
||||
yield DnsResponseSend(response, authoritative=True)
|
||||
|
||||
|
||||
class CookieHandler(ResponseHandler):
|
||||
def match(self, qctx: QueryContext) -> bool:
|
||||
example = dns.name.from_text("example")
|
||||
return qctx.qname.is_subdomain(example)
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[DnsResponseSend, None]:
|
||||
|
||||
qctx.prepare_new_response()
|
||||
|
||||
# Check for client cookie
|
||||
cookie = _get_cookie(qctx)
|
||||
|
||||
# If missing cookie entirely, just return SERVFAIL
|
||||
if cookie is None:
|
||||
qctx.response.set_rcode(dns.rcode.SERVFAIL)
|
||||
yield DnsResponseSend(qctx.response, authoritative=True)
|
||||
|
||||
# If there is a client cookie, mock BADCOOKIE to trigger
|
||||
# the resend loop logic.
|
||||
qctx.response.use_edns(options=[cookie])
|
||||
qctx.response.set_rcode(dns.rcode.BADCOOKIE)
|
||||
yield DnsResponseSend(qctx.response, authoritative=True)
|
||||
|
||||
|
||||
class NoErrorHandler(ResponseHandler):
|
||||
"""
|
||||
If the query is NOT a subdomain of example, respond with standard NOERROR empty answer
|
||||
"""
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[DnsResponseSend, None]:
|
||||
|
||||
qctx.prepare_new_response()
|
||||
qctx.response.set_rcode(dns.rcode.NOERROR)
|
||||
yield DnsResponseSend(qctx.response, authoritative=True)
|
||||
|
||||
|
||||
def resend_server() -> AsyncDnsServer:
|
||||
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)
|
||||
server.install_response_handlers(
|
||||
PrimeHandler(),
|
||||
CookieHandler(),
|
||||
NoErrorHandler(),
|
||||
)
|
||||
return server
|
||||
|
||||
|
||||
def main() -> None:
|
||||
resend_server().run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
16
bin/tests/system/resend_loop/ns4/named.conf.j2
Normal file
16
bin/tests/system/resend_loop/ns4/named.conf.j2
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
options {
|
||||
query-source address 10.53.0.4;
|
||||
notify-source 10.53.0.4;
|
||||
transfer-source 10.53.0.4;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.4; };
|
||||
listen-on-v6 { none; };
|
||||
recursion yes;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
zone "." IN {
|
||||
type hint;
|
||||
file "root.hint";
|
||||
};
|
||||
14
bin/tests/system/resend_loop/ns4/root.hint
Normal file
14
bin/tests/system/resend_loop/ns4/root.hint
Normal file
|
|
@ -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.
|
||||
|
||||
$TTL 999999
|
||||
. IN NS a.root-servers.nil.
|
||||
a.root-servers.nil. IN A 10.53.0.3
|
||||
28
bin/tests/system/resend_loop/tests_resend_loop.py
Normal file
28
bin/tests/system/resend_loop/tests_resend_loop.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import dns.message
|
||||
|
||||
import isctest
|
||||
|
||||
|
||||
def test_resend_loop_badcookie(ns4):
|
||||
expected_log = "exceeded max queries resolving 'test.example/A'"
|
||||
|
||||
msg = dns.message.make_query("test.example", "A")
|
||||
with ns4.watch_log_from_here() as watcher:
|
||||
res = isctest.query.udp(msg, ns4.ip)
|
||||
watcher.wait_for_line(expected_log)
|
||||
|
||||
isctest.check.servfail(res)
|
||||
|
||||
prohibited_log = "query failed (timed out) for test.example/IN/A"
|
||||
assert prohibited_log not in ns4.log
|
||||
|
|
@ -782,10 +782,12 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
|
|||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking NXDOMAIN is returned when querying non existing domain in CH class ($n)"
|
||||
echo_i "checking REFUSED is returned when querying non existing domain in CH class ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.1 id.hostname txt ch >dig.ns1.out.${n} || ret=1
|
||||
grep "status: NXDOMAIN" dig.ns1.out.${n} >/dev/null || ret=1
|
||||
dig_with_opts @10.53.0.1 hostname.chaostest txt ch >dig.ns1.out.1.${n} || ret=1
|
||||
grep "status: NOERROR" dig.ns1.out.1.${n} >/dev/null || ret=1
|
||||
dig_with_opts @10.53.0.1 id.hostname txt ch >dig.ns1.out.2.${n} || ret=1
|
||||
grep "status: REFUSED" dig.ns1.out.2.${n} >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
|
|
|
|||
28
bin/tests/system/selfpointedglue/ns1/named.conf.j2
Normal file
28
bin/tests/system/selfpointedglue/ns1/named.conf.j2
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type primary;
|
||||
file "root.db";
|
||||
};
|
||||
24
bin/tests/system/selfpointedglue/ns1/root.db
Normal file
24
bin/tests/system/selfpointedglue/ns1/root.db
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; SPDX-License-Identifier: MPL-2.0
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
;
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
$TTL 300
|
||||
. IN SOA owner.root-servers.nil. a.root.servers.nil. (
|
||||
2010 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
. NS a.root-servers.nil.
|
||||
a.root-servers.nil. A 10.53.0.1
|
||||
|
||||
tld. NS ns.tld.
|
||||
ns.tld. A 10.53.0.2
|
||||
28
bin/tests/system/selfpointedglue/ns2/named.conf.j2
Normal file
28
bin/tests/system/selfpointedglue/ns2/named.conf.j2
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.2;
|
||||
notify-source 10.53.0.2;
|
||||
transfer-source 10.53.0.2;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.2; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
zone "tld." {
|
||||
type primary;
|
||||
file "tld.db";
|
||||
};
|
||||
27
bin/tests/system/selfpointedglue/ns2/tld.db
Normal file
27
bin/tests/system/selfpointedglue/ns2/tld.db
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
tld. IN SOA owner.tld. ns.tld. (
|
||||
2010 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
tld. NS ns.tld.
|
||||
ns.tld. A 10.53.0.2
|
||||
|
||||
example.tld. NS ns.example.tld.
|
||||
ns.example.tld. A 10.53.0.3
|
||||
|
||||
example2.tld. NS ns.example2.tld.
|
||||
ns.example2.tld. A 10.53.0.3
|
||||
155
bin/tests/system/selfpointedglue/ns3/example.tld.db
Normal file
155
bin/tests/system/selfpointedglue/ns3/example.tld.db
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
example.tld. IN SOA owner.dnshoster.tld. ns.dnshoster.tld. (
|
||||
2010 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
|
||||
example.tld. NS ns.example.tld.
|
||||
ns.example.tld. A 10.53.0.3
|
||||
|
||||
sub.example.tld. NS ns01.sub.example.tld.
|
||||
sub.example.tld. NS ns02.sub.example.tld.
|
||||
sub.example.tld. NS ns03.sub.example.tld.
|
||||
sub.example.tld. NS ns04.sub.example.tld.
|
||||
sub.example.tld. NS ns05.sub.example.tld.
|
||||
sub.example.tld. NS ns06.sub.example.tld.
|
||||
sub.example.tld. NS ns07.sub.example.tld.
|
||||
sub.example.tld. NS ns08.sub.example.tld.
|
||||
sub.example.tld. NS ns09.sub.example.tld.
|
||||
sub.example.tld. NS ns10.sub.example.tld.
|
||||
|
||||
ns01.sub.example.tld. A 10.53.0.5
|
||||
ns01.sub.example.tld. A 10.53.0.6
|
||||
ns01.sub.example.tld. A 10.53.0.7
|
||||
ns01.sub.example.tld. A 10.53.0.8
|
||||
ns01.sub.example.tld. A 10.53.0.9
|
||||
ns01.sub.example.tld. A 10.53.0.10
|
||||
ns01.sub.example.tld. A 10.53.1.1
|
||||
ns01.sub.example.tld. A 10.53.1.2
|
||||
ns01.sub.example.tld. A 10.53.2.1
|
||||
ns01.sub.example.tld. A 10.53.0.3
|
||||
; Those RR (same below) pointing to 127.0.0.1 won't ever be used as they
|
||||
; exceeded the ADB limit.
|
||||
ns01.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns02.sub.example.tld. A 10.53.0.5
|
||||
ns02.sub.example.tld. A 10.53.0.6
|
||||
ns02.sub.example.tld. A 10.53.0.7
|
||||
ns02.sub.example.tld. A 10.53.0.8
|
||||
ns02.sub.example.tld. A 10.53.0.9
|
||||
ns02.sub.example.tld. A 10.53.0.10
|
||||
ns02.sub.example.tld. A 10.53.1.1
|
||||
ns02.sub.example.tld. A 10.53.1.2
|
||||
ns02.sub.example.tld. A 10.53.2.1
|
||||
ns02.sub.example.tld. A 10.53.0.3
|
||||
ns02.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns03.sub.example.tld. A 10.53.0.5
|
||||
ns03.sub.example.tld. A 10.53.0.6
|
||||
ns03.sub.example.tld. A 10.53.0.7
|
||||
ns03.sub.example.tld. A 10.53.0.8
|
||||
ns03.sub.example.tld. A 10.53.0.9
|
||||
ns03.sub.example.tld. A 10.53.0.10
|
||||
ns03.sub.example.tld. A 10.53.1.1
|
||||
ns03.sub.example.tld. A 10.53.1.2
|
||||
ns03.sub.example.tld. A 10.53.2.1
|
||||
ns03.sub.example.tld. A 10.53.0.3
|
||||
ns03.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns04.sub.example.tld. A 10.53.0.5
|
||||
ns04.sub.example.tld. A 10.53.0.6
|
||||
ns04.sub.example.tld. A 10.53.0.7
|
||||
ns04.sub.example.tld. A 10.53.0.8
|
||||
ns04.sub.example.tld. A 10.53.0.9
|
||||
ns04.sub.example.tld. A 10.53.0.10
|
||||
ns04.sub.example.tld. A 10.53.1.1
|
||||
ns04.sub.example.tld. A 10.53.1.2
|
||||
ns04.sub.example.tld. A 10.53.2.1
|
||||
ns04.sub.example.tld. A 10.53.0.3
|
||||
ns04.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns05.sub.example.tld. A 10.53.0.5
|
||||
ns05.sub.example.tld. A 10.53.0.6
|
||||
ns05.sub.example.tld. A 10.53.0.7
|
||||
ns05.sub.example.tld. A 10.53.0.8
|
||||
ns05.sub.example.tld. A 10.53.0.9
|
||||
ns05.sub.example.tld. A 10.53.0.10
|
||||
ns05.sub.example.tld. A 10.53.1.1
|
||||
ns05.sub.example.tld. A 10.53.1.2
|
||||
ns05.sub.example.tld. A 10.53.2.1
|
||||
ns05.sub.example.tld. A 10.53.0.3
|
||||
ns05.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns06.sub.example.tld. A 10.53.0.5
|
||||
ns06.sub.example.tld. A 10.53.0.6
|
||||
ns06.sub.example.tld. A 10.53.0.7
|
||||
ns06.sub.example.tld. A 10.53.0.8
|
||||
ns06.sub.example.tld. A 10.53.0.9
|
||||
ns06.sub.example.tld. A 10.53.0.10
|
||||
ns06.sub.example.tld. A 10.53.1.1
|
||||
ns06.sub.example.tld. A 10.53.1.2
|
||||
ns06.sub.example.tld. A 10.53.2.1
|
||||
ns06.sub.example.tld. A 10.53.0.3
|
||||
ns06.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns07.sub.example.tld. A 10.53.0.5
|
||||
ns07.sub.example.tld. A 10.53.0.6
|
||||
ns07.sub.example.tld. A 10.53.0.7
|
||||
ns07.sub.example.tld. A 10.53.0.8
|
||||
ns07.sub.example.tld. A 10.53.0.9
|
||||
ns07.sub.example.tld. A 10.53.0.10
|
||||
ns07.sub.example.tld. A 10.53.1.1
|
||||
ns07.sub.example.tld. A 10.53.1.2
|
||||
ns07.sub.example.tld. A 10.53.2.1
|
||||
ns07.sub.example.tld. A 10.53.0.3
|
||||
ns07.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns08.sub.example.tld. A 10.53.0.5
|
||||
ns08.sub.example.tld. A 10.53.0.6
|
||||
ns08.sub.example.tld. A 10.53.0.7
|
||||
ns08.sub.example.tld. A 10.53.0.8
|
||||
ns08.sub.example.tld. A 10.53.0.9
|
||||
ns08.sub.example.tld. A 10.53.0.10
|
||||
ns08.sub.example.tld. A 10.53.1.1
|
||||
ns08.sub.example.tld. A 10.53.1.2
|
||||
ns08.sub.example.tld. A 10.53.2.1
|
||||
ns08.sub.example.tld. A 10.53.0.3
|
||||
ns08.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns09.sub.example.tld. A 10.53.0.5
|
||||
ns09.sub.example.tld. A 10.53.0.6
|
||||
ns09.sub.example.tld. A 10.53.0.7
|
||||
ns09.sub.example.tld. A 10.53.0.8
|
||||
ns09.sub.example.tld. A 10.53.0.9
|
||||
ns09.sub.example.tld. A 10.53.0.10
|
||||
ns09.sub.example.tld. A 10.53.1.1
|
||||
ns09.sub.example.tld. A 10.53.1.2
|
||||
ns09.sub.example.tld. A 10.53.2.1
|
||||
ns09.sub.example.tld. A 10.53.0.3
|
||||
ns09.sub.example.tld. A 127.0.0.1
|
||||
|
||||
ns10.sub.example.tld. A 10.53.0.5
|
||||
ns10.sub.example.tld. A 10.53.0.6
|
||||
ns10.sub.example.tld. A 10.53.0.7
|
||||
ns10.sub.example.tld. A 10.53.0.8
|
||||
ns10.sub.example.tld. A 10.53.0.9
|
||||
ns10.sub.example.tld. A 10.53.0.10
|
||||
ns10.sub.example.tld. A 10.53.1.1
|
||||
ns10.sub.example.tld. A 10.53.1.2
|
||||
ns10.sub.example.tld. A 10.53.2.1
|
||||
ns10.sub.example.tld. A 10.53.0.3
|
||||
ns10.sub.example.tld. A 127.0.0.1
|
||||
33
bin/tests/system/selfpointedglue/ns3/example2.tld.db
Normal file
33
bin/tests/system/selfpointedglue/ns3/example2.tld.db
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
example2.tld. IN SOA owner.dnshoster.tld. ns.dnshoster.tld. (
|
||||
2010 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
|
||||
example2.tld. NS ns.example2.tld.
|
||||
ns.example2.tld. A 10.53.0.3
|
||||
|
||||
sub.example2.tld. NS ns01.sub.example2.tld.
|
||||
sub.example2.tld. NS ns02.sub.example2.tld.
|
||||
sub.example2.tld. NS ns03.sub.example2.tld.
|
||||
|
||||
ns01.sub.example2.tld. A 10.53.1.1
|
||||
ns01.sub.example2.tld. A 10.53.0.5
|
||||
ns02.sub.example2.tld. A 10.53.1.2
|
||||
ns02.sub.example2.tld. A 10.53.0.6
|
||||
ns03.sub.example2.tld. A 10.53.2.1
|
||||
ns03.sub.example2.tld. A 10.53.0.7
|
||||
44
bin/tests/system/selfpointedglue/ns3/named.conf.j2
Normal file
44
bin/tests/system/selfpointedglue/ns3/named.conf.j2
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.3;
|
||||
notify-source 10.53.0.3;
|
||||
transfer-source 10.53.0.3;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on {
|
||||
10.53.0.3;
|
||||
10.53.0.5;
|
||||
10.53.0.6;
|
||||
10.53.0.7;
|
||||
10.53.0.8;
|
||||
10.53.0.9;
|
||||
10.53.0.10;
|
||||
10.53.1.1;
|
||||
10.53.1.2;
|
||||
10.53.2.1;
|
||||
};
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
};
|
||||
|
||||
zone "example.tld." {
|
||||
type primary;
|
||||
file "example.tld.db";
|
||||
};
|
||||
|
||||
zone "example2.tld." {
|
||||
type primary;
|
||||
file "example2.tld.db";
|
||||
};
|
||||
3
bin/tests/system/selfpointedglue/ns4/named.args.j2
Normal file
3
bin/tests/system/selfpointedglue/ns4/named.args.j2
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{% set adblimit = adblimit | default("") %}
|
||||
|
||||
-D selfpointedglue-ns4 -m record -c named.conf -d 99 -g -T maxcachesize=2097152 -4 @adblimit@
|
||||
59
bin/tests/system/selfpointedglue/ns4/named.conf.j2
Normal file
59
bin/tests/system/selfpointedglue/ns4/named.conf.j2
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
{% set maxdelegationservers = maxdelegationservers | default(None) %}
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.4;
|
||||
notify-source 10.53.0.4;
|
||||
transfer-source 10.53.0.4;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.4; };
|
||||
recursion yes;
|
||||
dnssec-validation no;
|
||||
dnstap { resolver query; };
|
||||
dnstap-output file "dnstap.out";
|
||||
{% if maxdelegationservers %}
|
||||
@maxdelegationservers@
|
||||
{% endif %}
|
||||
};
|
||||
|
||||
/*
|
||||
* Forcing TCP ensures that ADDITIONAL won't be truncated (responses won't have
|
||||
* the TC flag, hence the resolver won't retry using TCP by itself, see
|
||||
* https://datatracker.ietf.org/doc/html/rfc2181#section-9)
|
||||
*/
|
||||
server 10.53.0.3 { tcp-only true; };
|
||||
server 10.53.0.5 { tcp-only true; };
|
||||
server 10.53.0.6 { tcp-only true; };
|
||||
server 10.53.0.7 { tcp-only true; };
|
||||
server 10.53.0.8 { tcp-only true; };
|
||||
server 10.53.0.9 { tcp-only true; };
|
||||
server 10.53.0.10 { tcp-only true; };
|
||||
server 10.53.1.1 { tcp-only true; };
|
||||
server 10.53.1.2 { tcp-only true; };
|
||||
server 10.53.2.1 { tcp-only true; };
|
||||
|
||||
zone "." {
|
||||
type hint;
|
||||
file "root.hint";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
14
bin/tests/system/selfpointedglue/ns4/root.hint
Normal file
14
bin/tests/system/selfpointedglue/ns4/root.hint
Normal file
|
|
@ -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.
|
||||
|
||||
$TTL 999999
|
||||
. IN NS a.root-servers.nil.
|
||||
a.root-servers.nil. IN A 10.53.0.1
|
||||
122
bin/tests/system/selfpointedglue/tests_selfpointedglue.py
Normal file
122
bin/tests/system/selfpointedglue/tests_selfpointedglue.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import isctest
|
||||
import isctest.mark
|
||||
|
||||
pytestmark = [isctest.mark.with_dnstap]
|
||||
|
||||
|
||||
def line_to_ips_and_queries(line):
|
||||
# dnstap-read output line example
|
||||
# 05-Feb-2026 11:00:57.853 RQ 10.53.0.4:38507 -> 10.53.0.3:22047 TCP 56b sub.example.tld/IN/NS
|
||||
_, _, _, _, _, dst, _, _, query = line.split(" ", 9)
|
||||
ip, _ = dst.split(":", 1)
|
||||
return (ip, query)
|
||||
|
||||
|
||||
def extract_dnstap(ns, expectedlen):
|
||||
ns.rndc("dnstap -roll 1")
|
||||
path = os.path.join(ns.identifier, "dnstap.out.0")
|
||||
dnstapread = isctest.run.cmd(
|
||||
[isctest.vars.ALL["DNSTAPREAD"], path],
|
||||
)
|
||||
|
||||
lines = dnstapread.out.splitlines()
|
||||
assert expectedlen == len(lines)
|
||||
return list(map(line_to_ips_and_queries, lines))
|
||||
|
||||
|
||||
# Because DNSTAP doesn't have ordering guarantee, the order doesn't matter here.
|
||||
def expect_ip_and_query(expected_ips_and_queries, ips_and_queries):
|
||||
found_count = 0
|
||||
for expected_ip, expected_query in expected_ips_and_queries:
|
||||
found = False
|
||||
for ip, query in ips_and_queries:
|
||||
if ip == expected_ip and query == expected_query:
|
||||
found = True
|
||||
found_count += 1
|
||||
break
|
||||
assert found
|
||||
assert found_count == len(expected_ips_and_queries)
|
||||
|
||||
|
||||
def test_selfpointedglue(ns4):
|
||||
msg = isctest.query.create("a.sub.example.tld.", "A")
|
||||
res = isctest.query.tcp(msg, ns4.ip)
|
||||
isctest.check.servfail(res)
|
||||
|
||||
ips_and_queries = extract_dnstap(ns4, 10)
|
||||
|
||||
# Thanks to the de-duplication, only the first 6 NS IPs are
|
||||
# queried (once sub.example.tld. NS is found) instead of 60
|
||||
# (60 per NS, with 10 NS).
|
||||
expect_ip_and_query(
|
||||
[
|
||||
("10.53.0.1", "./IN/NS"),
|
||||
("10.53.0.1", "tld/IN/NS"),
|
||||
("10.53.0.2", "example.tld/IN/NS"),
|
||||
("10.53.0.3", "sub.example.tld/IN/NS"),
|
||||
("10.53.0.3", "a.sub.example.tld/IN/A"),
|
||||
("10.53.0.5", "a.sub.example.tld/IN/A"),
|
||||
("10.53.0.6", "a.sub.example.tld/IN/A"),
|
||||
("10.53.0.7", "a.sub.example.tld/IN/A"),
|
||||
("10.53.0.8", "a.sub.example.tld/IN/A"),
|
||||
("10.53.0.9", "a.sub.example.tld/IN/A"),
|
||||
],
|
||||
ips_and_queries,
|
||||
)
|
||||
|
||||
|
||||
def test_selfpointedglue_adblimit(ns4, templates):
|
||||
templates.render("ns4/named.args", {"adblimit": "-T adbaddrslimit=2"})
|
||||
with ns4.watch_log_from_here() as watcher:
|
||||
# Server needs a full stop/restart to read the new command line options.
|
||||
ns4.stop()
|
||||
ns4.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
|
||||
watcher.wait_for_line("running")
|
||||
|
||||
msg = isctest.query.create("a.sub.example.tld.", "A")
|
||||
res = isctest.query.tcp(msg, ns4.ip)
|
||||
isctest.check.servfail(res)
|
||||
|
||||
ips_and_queries = extract_dnstap(ns4, 6)
|
||||
|
||||
expect_ip_and_query(
|
||||
[
|
||||
("10.53.0.1", "./IN/NS"),
|
||||
("10.53.0.1", "tld/IN/NS"),
|
||||
("10.53.0.2", "example.tld/IN/NS"),
|
||||
("10.53.0.3", "sub.example.tld/IN/NS"),
|
||||
# Because of the ADB limit, only 2 IP are used instead
|
||||
# of the 10 provided ones.
|
||||
("10.53.0.3", "a.sub.example.tld/IN/A"),
|
||||
("10.53.0.5", "a.sub.example.tld/IN/A"),
|
||||
],
|
||||
ips_and_queries,
|
||||
)
|
||||
|
||||
|
||||
def test_selfpointedglue_adblimitlower(ns4, templates):
|
||||
templates.render("ns4/named.args", {"adblimit": "-T adbaddrslimit=0"})
|
||||
with ns4.watch_log_from_here() as watcher:
|
||||
# Server needs a full stop/restart to read the new command line options.
|
||||
ns4.stop()
|
||||
failed_to_start = False
|
||||
try:
|
||||
ns4.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
|
||||
except subprocess.CalledProcessError as _:
|
||||
failed_to_start = True
|
||||
assert failed_to_start is True
|
||||
watcher.wait_for_line("adbaddrslimit must be at least 1")
|
||||
18
bin/tests/system/srtt/README
Normal file
18
bin/tests/system/srtt/README
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
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.
|
||||
|
||||
ns1 is root
|
||||
|
||||
ans{2-5} simulates four NS servers making authority on the same domain
|
||||
`example.`. ans2 is the quickest to answer, followed by ans3, then ans4, with
|
||||
ans5 being the slowest.
|
||||
|
||||
ns6 is a resolver
|
||||
36
bin/tests/system/srtt/ans2/ans.py
Normal file
36
bin/tests/system/srtt/ans2/ans.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"""
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See the COPYRIGHT file distributed with this work for additional
|
||||
information regarding copyright ownership.
|
||||
"""
|
||||
|
||||
import dns.rcode
|
||||
|
||||
from isctest.asyncserver import AsyncDnsServer, IgnoreAllQueries
|
||||
|
||||
from ..srtt_ans import DelayedQnameRangeHandler
|
||||
|
||||
|
||||
class Foo1ToFoo99Handler(DelayedQnameRangeHandler):
|
||||
max_qname = 99
|
||||
delay = 0.0
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)
|
||||
server.install_response_handlers(
|
||||
Foo1ToFoo99Handler(),
|
||||
IgnoreAllQueries(),
|
||||
)
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
36
bin/tests/system/srtt/ans3/ans.py
Normal file
36
bin/tests/system/srtt/ans3/ans.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"""
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See the COPYRIGHT file distributed with this work for additional
|
||||
information regarding copyright ownership.
|
||||
"""
|
||||
|
||||
import dns.rcode
|
||||
|
||||
from isctest.asyncserver import AsyncDnsServer, IgnoreAllQueries
|
||||
|
||||
from ..srtt_ans import DelayedQnameRangeHandler
|
||||
|
||||
|
||||
class Foo1ToFoo199Handler(DelayedQnameRangeHandler):
|
||||
max_qname = 199
|
||||
delay = 0.03
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)
|
||||
server.install_response_handlers(
|
||||
Foo1ToFoo199Handler(),
|
||||
IgnoreAllQueries(),
|
||||
)
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
36
bin/tests/system/srtt/ans4/ans.py
Normal file
36
bin/tests/system/srtt/ans4/ans.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"""
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See the COPYRIGHT file distributed with this work for additional
|
||||
information regarding copyright ownership.
|
||||
"""
|
||||
|
||||
import dns.rcode
|
||||
|
||||
from isctest.asyncserver import AsyncDnsServer, IgnoreAllQueries
|
||||
|
||||
from ..srtt_ans import DelayedQnameRangeHandler
|
||||
|
||||
|
||||
class Foo1ToFoo299Handler(DelayedQnameRangeHandler):
|
||||
max_qname = 299
|
||||
delay = 0.08
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)
|
||||
server.install_response_handlers(
|
||||
Foo1ToFoo299Handler(),
|
||||
IgnoreAllQueries(),
|
||||
)
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
36
bin/tests/system/srtt/ans5/ans.py
Normal file
36
bin/tests/system/srtt/ans5/ans.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"""
|
||||
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See the COPYRIGHT file distributed with this work for additional
|
||||
information regarding copyright ownership.
|
||||
"""
|
||||
|
||||
import dns.rcode
|
||||
|
||||
from isctest.asyncserver import AsyncDnsServer, IgnoreAllQueries
|
||||
|
||||
from ..srtt_ans import DelayedQnameRangeHandler
|
||||
|
||||
|
||||
class Foo1ToFoo399Handler(DelayedQnameRangeHandler):
|
||||
max_qname = 399
|
||||
delay = 0.15
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)
|
||||
server.install_response_handlers(
|
||||
Foo1ToFoo399Handler(),
|
||||
IgnoreAllQueries(),
|
||||
)
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
29
bin/tests/system/srtt/ns1/named.conf.j2
Normal file
29
bin/tests/system/srtt/ns1/named.conf.j2
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
notify yes;
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type primary;
|
||||
file "root.db";
|
||||
};
|
||||
36
bin/tests/system/srtt/ns1/root.db
Normal file
36
bin/tests/system/srtt/ns1/root.db
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
. IN SOA owner.root-servers.nil. a.root-servers.nil. (
|
||||
2000042100 ; serial
|
||||
600 ; refresh
|
||||
600 ; retry
|
||||
1200 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
. NS a.root-servers.nil.
|
||||
a.root-servers.nil. A 10.53.0.1
|
||||
|
||||
; The idea is that the resolver would do 2 ADB lookups, so there would be 2
|
||||
; find list, both with 2 IPs in it. ns1 (which is actually ans2 and ans5) would
|
||||
; have both the slowest and fastest addresses. ns2 (which is actually ans3 and
|
||||
; ans4) would have two addresses in the middle.
|
||||
|
||||
example. NS ns1.example.
|
||||
example. NS ns1.example.
|
||||
example. NS ns2.example.
|
||||
example. NS ns2.example.
|
||||
|
||||
ns1.example. A 10.53.0.2 ; delay is 0
|
||||
ns1.example. A 10.53.0.5 ; delay is 0.15
|
||||
ns2.example. A 10.53.0.4 ; delay is 0.08
|
||||
ns2.example. A 10.53.0.3 ; delay is 0.03
|
||||
1
bin/tests/system/srtt/ns6/named.args
Normal file
1
bin/tests/system/srtt/ns6/named.args
Normal file
|
|
@ -0,0 +1 @@
|
|||
-D srtt-ns6 -m record -c named.conf -d 99 -g -T maxcachesize=2097152 -4
|
||||
41
bin/tests/system/srtt/ns6/named.conf.j2
Normal file
41
bin/tests/system/srtt/ns6/named.conf.j2
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.6;
|
||||
notify-source 10.53.0.6;
|
||||
transfer-source 10.53.0.6;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.6; };
|
||||
listen-on-v6 { none; };
|
||||
recursion yes;
|
||||
dnssec-validation no;
|
||||
dnstap { resolver query; };
|
||||
dnstap-output file "dnstap.out";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type hint;
|
||||
file "../../_common/root.hint";
|
||||
};
|
||||
59
bin/tests/system/srtt/srtt_ans.py
Normal file
59
bin/tests/system/srtt/srtt_ans.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
"""
|
||||
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 collections.abc import AsyncGenerator
|
||||
|
||||
import abc
|
||||
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.rrset
|
||||
|
||||
from isctest.asyncserver import DnsResponseSend, QnameQtypeHandler, QueryContext
|
||||
|
||||
|
||||
class DelayedQnameRangeHandler(QnameQtypeHandler):
|
||||
"""
|
||||
Respond to queries for QNAMEs "foo1.example." through "foo<N>.example."
|
||||
with QTYPE=A, where <N> must be defined by the subclass. Every response is
|
||||
delayed by a fixed amount of time, which must also be defined (in seconds)
|
||||
by the subclass.
|
||||
"""
|
||||
|
||||
@property
|
||||
def qnames(self) -> list[str]:
|
||||
return [f"foo{x}.example." for x in range(1, self.max_qname + 1)]
|
||||
|
||||
qtypes = [dns.rdatatype.A]
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def max_qname(self) -> int:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def delay(self) -> float:
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.__class__.__name__}(foo[1-{self.max_qname}].example/A)"
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[DnsResponseSend, None]:
|
||||
a_rrset = dns.rrset.from_text(
|
||||
qctx.qname, 300, dns.rdataclass.IN, dns.rdatatype.A, "10.53.9.9"
|
||||
)
|
||||
qctx.response.answer.append(a_rrset)
|
||||
yield DnsResponseSend(qctx.response, delay=self.delay)
|
||||
89
bin/tests/system/srtt/tests_srtt.py
Normal file
89
bin/tests/system/srtt/tests_srtt.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import os
|
||||
|
||||
import isctest
|
||||
import isctest.mark
|
||||
|
||||
pytestmark = [isctest.mark.with_dnstap]
|
||||
|
||||
|
||||
def line_to_dst_ips(line):
|
||||
# dnstap-read output line example
|
||||
# 05-Feb-2026 11:00:57.853 RQ 10.53.0.6:38507 -> 10.53.0.3:22047 TCP 56b fooXXX.example./IN/NS
|
||||
_, _, _, _, _, dst, _, _, _ = line.split(" ", 9)
|
||||
ip, _ = dst.split(":", 1)
|
||||
return ip
|
||||
|
||||
|
||||
def extract_dnstap(ns):
|
||||
ns.rndc("dnstap -roll 1")
|
||||
path = os.path.join(ns.identifier, "dnstap.out.0")
|
||||
dnstapread = isctest.run.cmd(
|
||||
[isctest.vars.ALL["DNSTAPREAD"], path],
|
||||
)
|
||||
|
||||
lines = dnstapread.out.splitlines()
|
||||
return map(line_to_dst_ips, lines)
|
||||
|
||||
|
||||
def assert_used_auth(ns, authip):
|
||||
ips = extract_dnstap(ns)
|
||||
queries = 0
|
||||
matches = 0
|
||||
for ip in ips:
|
||||
queries += 1
|
||||
if ip == authip:
|
||||
matches += 1
|
||||
assert matches > 85
|
||||
assert queries <= 115
|
||||
|
||||
|
||||
def test_srtt(ns6):
|
||||
for i in range(1, 100):
|
||||
msg = isctest.query.create(f"foo{i}.example.", "A")
|
||||
res = isctest.query.udp(msg, ns6.ip)
|
||||
isctest.check.noerror(res)
|
||||
assert len(res.answer[0]) == 1
|
||||
res.answer[0].ttl = 300
|
||||
assert str(res.answer[0]) == f"foo{i}.example. 300 IN A 10.53.9.9"
|
||||
|
||||
assert_used_auth(ns6, "10.53.0.2")
|
||||
|
||||
for i in range(100, 200):
|
||||
msg = isctest.query.create(f"foo{i}.example.", "A")
|
||||
res = isctest.query.udp(msg, ns6.ip)
|
||||
isctest.check.noerror(res)
|
||||
assert len(res.answer[0]) == 1
|
||||
res.answer[0].ttl = 300
|
||||
assert str(res.answer[0]) == f"foo{i}.example. 300 IN A 10.53.9.9"
|
||||
|
||||
assert_used_auth(ns6, "10.53.0.3")
|
||||
|
||||
for i in range(200, 300):
|
||||
msg = isctest.query.create(f"foo{i}.example.", "A")
|
||||
res = isctest.query.udp(msg, ns6.ip)
|
||||
isctest.check.noerror(res)
|
||||
assert len(res.answer[0]) == 1
|
||||
res.answer[0].ttl = 300
|
||||
assert str(res.answer[0]) == f"foo{i}.example. 300 IN A 10.53.9.9"
|
||||
|
||||
assert_used_auth(ns6, "10.53.0.4")
|
||||
|
||||
for i in range(300, 400):
|
||||
msg = isctest.query.create(f"foo{i}.example.", "A")
|
||||
res = isctest.query.udp(msg, ns6.ip)
|
||||
isctest.check.noerror(res)
|
||||
assert len(res.answer[0]) == 1
|
||||
res.answer[0].ttl = 300
|
||||
assert str(res.answer[0]) == f"foo{i}.example. 300 IN A 10.53.9.9"
|
||||
assert_used_auth(ns6, "10.53.0.5")
|
||||
BIN
bin/tests/system/tkeyleak/ns1/dns.keytab
Normal file
BIN
bin/tests/system/tkeyleak/ns1/dns.keytab
Normal file
Binary file not shown.
21
bin/tests/system/tkeyleak/ns1/example.db.in
Normal file
21
bin/tests/system/tkeyleak/ns1/example.db.in
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
@ IN SOA ns.example. admin.example. (
|
||||
1 ; serial
|
||||
3600 ; refresh
|
||||
900 ; retry
|
||||
604800 ; expire
|
||||
300 ; minimum
|
||||
)
|
||||
@ IN NS ns.example.
|
||||
ns IN A 10.53.0.1
|
||||
39
bin/tests/system/tkeyleak/ns1/named.conf.j2
Normal file
39
bin/tests/system/tkeyleak/ns1/named.conf.j2
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
tkey-gssapi-keytab "dns.keytab";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
zone "example" {
|
||||
type primary;
|
||||
file "example.db";
|
||||
};
|
||||
21
bin/tests/system/tkeyleak/prereq.sh
Normal file
21
bin/tests/system/tkeyleak/prereq.sh
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
. ../conf.sh
|
||||
|
||||
$FEATURETEST --gssapi || {
|
||||
echo_i "gssapi not supported - skipping tkeyleak test"
|
||||
exit 255
|
||||
}
|
||||
|
||||
exit 0
|
||||
17
bin/tests/system/tkeyleak/setup.sh
Normal file
17
bin/tests/system/tkeyleak/setup.sh
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# shellcheck source=conf.sh
|
||||
. ../conf.sh
|
||||
|
||||
cp ns1/example.db.in ns1/example.db
|
||||
145
bin/tests/system/tkeyleak/tests_tkeyleak.py
Normal file
145
bin/tests/system/tkeyleak/tests_tkeyleak.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
# 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.
|
||||
|
||||
"""
|
||||
Regression test for GSS-API context leak via repeated TKEY queries.
|
||||
|
||||
An unauthenticated attacker could exhaust server memory by sending
|
||||
repeated TKEY queries with crafted SPNEGO NegTokenInit tokens.
|
||||
Each query triggers gss_accept_sec_context() which returns
|
||||
GSS_S_CONTINUE_NEEDED and allocates a GSS context. On the unfixed
|
||||
code path, the context handle in process_gsstkey() is never stored
|
||||
or freed, leaking ~520 bytes per query.
|
||||
|
||||
The fix rejects GSS_S_CONTINUE_NEEDED in dst_gssapi_acceptctx() and
|
||||
deletes the context immediately.
|
||||
|
||||
The key distinguishing signal in the TKEY response:
|
||||
- CONTINUE (vulnerable): error=0, output token present, no TSIG
|
||||
- BADKEY (fixed): error=17, no output token
|
||||
"""
|
||||
|
||||
import struct
|
||||
import time
|
||||
|
||||
import dns.name
|
||||
import dns.query
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.rdtypes.ANY.TKEY
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"*/*.db",
|
||||
]
|
||||
)
|
||||
|
||||
TKEY_NAME = dns.name.from_text("test.key.")
|
||||
GSSAPI_ALGORITHM = dns.name.from_text("gss-tsig.")
|
||||
TKEY_MODE_GSSAPI = 3
|
||||
|
||||
# OID 1.2.840.113554.1.2.2 (Kerberos 5)
|
||||
KRB5_OID = b"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
|
||||
|
||||
# OID 1.3.6.1.5.5.2 (SPNEGO)
|
||||
SPNEGO_OID = b"\x06\x06\x2b\x06\x01\x05\x05\x02"
|
||||
|
||||
|
||||
def der_encode(tag, data):
|
||||
"""Encode data in ASN.1 DER TLV format."""
|
||||
length = len(data)
|
||||
if length < 128:
|
||||
return tag + bytes([length]) + data
|
||||
if length < 256:
|
||||
return tag + b"\x81" + bytes([length]) + data
|
||||
return tag + b"\x82" + struct.pack(">H", length) + data
|
||||
|
||||
|
||||
def spnego_negtokeninit():
|
||||
"""Build a SPNEGO NegTokenInit proposing krb5 without a mechToken.
|
||||
|
||||
This forces gss_accept_sec_context() to return GSS_S_CONTINUE_NEEDED
|
||||
because the acceptor recognizes the krb5 mechanism but has not
|
||||
received an actual AP-REQ token yet.
|
||||
"""
|
||||
# MechTypeList ::= SEQUENCE OF MechType
|
||||
mechtype_list = der_encode(b"\x30", KRB5_OID)
|
||||
# [0] mechTypes
|
||||
mechtypes = der_encode(b"\xa0", mechtype_list)
|
||||
# NegTokenInit ::= SEQUENCE { mechTypes, ... }
|
||||
negtokeninit = der_encode(b"\x30", mechtypes)
|
||||
# [0] CONSTRUCTED (wrapping NegTokenInit)
|
||||
wrapped = der_encode(b"\xa0", negtokeninit)
|
||||
# APPLICATION 0 CONSTRUCTED (SPNEGO OID + body)
|
||||
return der_encode(b"\x60", SPNEGO_OID + wrapped)
|
||||
|
||||
|
||||
def make_tkey_query(token):
|
||||
"""Build a TKEY query with a GSS-API token in the additional section."""
|
||||
now = int(time.time())
|
||||
tkey_rdata = dns.rdtypes.ANY.TKEY.TKEY(
|
||||
rdclass=dns.rdataclass.ANY,
|
||||
rdtype=dns.rdatatype.TKEY,
|
||||
algorithm=GSSAPI_ALGORITHM,
|
||||
inception=now,
|
||||
expiration=now + 86400,
|
||||
mode=TKEY_MODE_GSSAPI,
|
||||
error=0,
|
||||
key=token,
|
||||
other=b"",
|
||||
)
|
||||
|
||||
msg = isctest.query.create(TKEY_NAME, dns.rdatatype.TKEY, dns.rdataclass.ANY)
|
||||
rrset = msg.find_rrset(
|
||||
msg.additional,
|
||||
TKEY_NAME,
|
||||
dns.rdataclass.ANY,
|
||||
dns.rdatatype.TKEY,
|
||||
create=True,
|
||||
)
|
||||
rrset.add(tkey_rdata)
|
||||
return msg
|
||||
|
||||
|
||||
def test_tkey_gssapi_no_continuation(ns1):
|
||||
"""TKEY with a SPNEGO NegTokenInit must be rejected, not continued.
|
||||
|
||||
On unfixed code, gss_accept_sec_context() returns CONTINUE_NEEDED
|
||||
and the response has error=0 with an output token (the leaked path).
|
||||
On fixed code, CONTINUE_NEEDED is rejected and the response has
|
||||
error=BADKEY(17) with no output token.
|
||||
"""
|
||||
port = ns1.ports.dns
|
||||
ip = ns1.ip
|
||||
|
||||
msg = make_tkey_query(spnego_negtokeninit())
|
||||
res = dns.query.tcp(msg, ip, port=port, timeout=5)
|
||||
|
||||
assert res is not None
|
||||
|
||||
tkey = get_tkey_answer(res)
|
||||
assert tkey is not None, "server did not return a TKEY answer"
|
||||
assert (
|
||||
tkey.error != 0
|
||||
), "server returned error=0 (GSS_S_CONTINUE_NEEDED not rejected)"
|
||||
assert len(tkey.key) == 0, "server returned a continuation token"
|
||||
|
||||
|
||||
def get_tkey_answer(response):
|
||||
"""Extract TKEY rdata from a DNS response, or None."""
|
||||
for rrset in response.answer:
|
||||
if rrset.rdtype == dns.rdatatype.TKEY:
|
||||
for rdata in rrset:
|
||||
return rdata
|
||||
return None
|
||||
|
|
@ -25,6 +25,11 @@ dig_cmd() {
|
|||
"$DIG" $DIGOPTS "$@" | grep -v '^;'
|
||||
}
|
||||
|
||||
dig_full() {
|
||||
# shellcheck disable=SC2086
|
||||
"$DIG" $DIGOPTS "$@"
|
||||
}
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "querying for various representations of an IN A record ($n)"
|
||||
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
|
||||
|
|
@ -81,8 +86,8 @@ n=$((n + 1))
|
|||
echo_i "querying for various representations of a CLASS10 TYPE1 record ($n)"
|
||||
for i in 1 2; do
|
||||
ret=0
|
||||
dig_cmd +short @10.53.0.1 a$i.example a class10 >dig.out.$i.test$n
|
||||
echo '\# 4 0A000001' | diff - dig.out.$i.test$n || ret=1
|
||||
dig_full @10.53.0.1 a$i.example a class10 >dig.out.$i.test$n
|
||||
grep -q "NOTIMP" dig.out.$i.test$n || ret=1
|
||||
if [ $ret != 0 ]; then
|
||||
echo_i "#$i failed"
|
||||
fi
|
||||
|
|
@ -93,8 +98,8 @@ n=$((n + 1))
|
|||
echo_i "querying for various representations of a CLASS10 TXT record ($n)"
|
||||
for i in 1 2 3 4; do
|
||||
ret=0
|
||||
dig_cmd +short @10.53.0.1 txt$i.example txt class10 >dig.out.$i.test$n
|
||||
echo '"hello"' | diff - dig.out.$i.test$n || ret=1
|
||||
dig_full @10.53.0.1 txt$i.example txt class10 >dig.out.$i.test$n
|
||||
grep -q "NOTIMP" dig.out.$i.test$n || ret=1
|
||||
if [ $ret != 0 ]; then
|
||||
echo_i "#$i failed"
|
||||
fi
|
||||
|
|
@ -105,8 +110,8 @@ n=$((n + 1))
|
|||
echo_i "querying for various representations of a CLASS10 TYPE123 record ($n)"
|
||||
for i in 1 2; do
|
||||
ret=0
|
||||
dig_cmd +short @10.53.0.1 unk$i.example type123 class10 >dig.out.$i.test$n
|
||||
echo '\# 1 00' | diff - dig.out.$i.test$n || ret=1
|
||||
dig_full @10.53.0.1 unk$i.example type123 class10 >dig.out.$i.test$n
|
||||
grep -q "NOTIMP" dig.out.$i.test$n || ret=1
|
||||
if [ $ret != 0 ]; then
|
||||
echo_i "#$i failed"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ options {
|
|||
recursion no;
|
||||
dnssec-validation no;
|
||||
notify yes;
|
||||
|
||||
transfers-out 3;
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
|
|
|
|||
46
bin/tests/system/xferquota/ns3/named.conf.j2
Normal file
46
bin/tests/system/xferquota/ns3/named.conf.j2
Normal file
|
|
@ -0,0 +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.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.3;
|
||||
notify-source 10.53.0.3;
|
||||
transfer-source 10.53.0.3;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
dnssec-validation no;
|
||||
|
||||
transfers-out 1;
|
||||
allow-transfer { 10.53.0.2; };
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
zone "." {
|
||||
type primary;
|
||||
file "root.db";
|
||||
};
|
||||
|
||||
zone "quota." {
|
||||
type primary;
|
||||
file "quota.db";
|
||||
};
|
||||
22
bin/tests/system/xferquota/ns3/quota.db
Normal file
22
bin/tests/system/xferquota/ns3/quota.db
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
@ IN SOA ns1.quota. hostmaster.quota. (
|
||||
1 ; serial
|
||||
3600 ; refresh
|
||||
1800 ; retry
|
||||
604800 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
IN NS ns1.quota.
|
||||
ns1 IN A 10.53.0.3
|
||||
www IN A 10.0.0.1
|
||||
21
bin/tests/system/xferquota/ns3/root.db
Normal file
21
bin/tests/system/xferquota/ns3/root.db
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
; 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.
|
||||
|
||||
$TTL 300
|
||||
. IN SOA ns.root. hostmaster.root. (
|
||||
1 ; serial
|
||||
3600 ; refresh
|
||||
1800 ; retry
|
||||
604800 ; expire
|
||||
600 ; minimum
|
||||
)
|
||||
. NS a.root-servers.nil.
|
||||
a.root-servers.nil. A 10.53.0.3
|
||||
|
|
@ -12,12 +12,15 @@
|
|||
from re import compile as Re
|
||||
|
||||
import glob
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import signal
|
||||
import time
|
||||
|
||||
import dns.message
|
||||
import dns.query
|
||||
import dns.zone
|
||||
import pytest
|
||||
|
||||
|
|
@ -60,6 +63,9 @@ def test_xferquota(named_port, ns1, ns2):
|
|||
matching_line_count += 1
|
||||
return matching_line_count == 300
|
||||
|
||||
# The primary has 'transfers-out 3;', while the secondary has
|
||||
# 'transfers-in 5; transfer-per-ns 5;'. This will allow all the zones
|
||||
# to be eventually transferred, hitting the quotas now and then.
|
||||
isctest.run.retry_with_timeout(check_line_count, timeout=360)
|
||||
|
||||
axfr_msg = isctest.query.create("zone000099.example.", "AXFR")
|
||||
|
|
@ -79,3 +85,39 @@ def test_xferquota(named_port, ns1, ns2):
|
|||
with ns2.watch_log_from_start(timeout=30) as watcher:
|
||||
watcher.wait_for_line(pattern)
|
||||
query_and_compare(a_msg)
|
||||
|
||||
|
||||
def _flood_unauthorized_axfrs(port, duration):
|
||||
"""Child process: send unauthorized AXFR requests for `duration` seconds."""
|
||||
deadline = time.monotonic() + duration
|
||||
while time.monotonic() < deadline:
|
||||
try:
|
||||
msg = dns.message.make_query("quota.", "AXFR")
|
||||
dns.query.tcp(msg, "10.53.0.3", port=port, timeout=2, source="10.53.0.1")
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
pass
|
||||
|
||||
|
||||
def test_xfrquota_unauthorized_no_starve(named_port):
|
||||
"""Unauthorized AXFR clients must not consume XFR-out quota (GL #3859).
|
||||
|
||||
ns3 is configured with transfers-out 1 and allow-transfer { 10.53.0.2; }.
|
||||
We flood AXFR requests from unauthorized source processes (10.53.0.1) and
|
||||
verify that an authorized client (10.53.0.2) can still transfer.
|
||||
"""
|
||||
with multiprocessing.Pool(10) as pool:
|
||||
pool.starmap_async(_flood_unauthorized_axfrs, [(named_port, 5)] * 10)
|
||||
|
||||
# Give the flood a moment to saturate
|
||||
time.sleep(1)
|
||||
|
||||
# Try an authorized AXFR from 10.53.0.2 multiple times to increase
|
||||
# the chance of hitting the race window where quota is consumed.
|
||||
zone = dns.zone.Zone("quota.")
|
||||
dns.query.inbound_xfr(
|
||||
"10.53.0.3",
|
||||
zone,
|
||||
port=named_port,
|
||||
timeout=10,
|
||||
source="10.53.0.2",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ Changelog
|
|||
development. Regular users should refer to :ref:`Release Notes <relnotes>`
|
||||
for changes relevant to them.
|
||||
|
||||
.. include:: ../changelog/changelog-9.20.23.rst
|
||||
.. include:: ../changelog/changelog-9.20.22.rst
|
||||
.. include:: ../changelog/changelog-9.20.21.rst
|
||||
.. include:: ../changelog/changelog-9.20.20.rst
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ The list of known issues affecting the latest version in the 9.20 branch can be
|
|||
found at
|
||||
https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.20
|
||||
|
||||
.. include:: ../notes/notes-9.20.23.rst
|
||||
.. include:: ../notes/notes-9.20.22.rst
|
||||
.. include:: ../notes/notes-9.20.21.rst
|
||||
.. include:: ../notes/notes-9.20.20.rst
|
||||
|
|
|
|||
369
doc/changelog/changelog-9.20.23.rst
Normal file
369
doc/changelog/changelog-9.20.23.rst
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
.. 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.20.23
|
||||
------------
|
||||
|
||||
Security Fixes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- Fix outgoing zone transfers' quota issue. ``1006b044b7``
|
||||
|
||||
Unauthorized clients could consume outgoing zone transfers quota and
|
||||
block authorized zone transfer clients. This has been fixed.
|
||||
:gl:`#3589`
|
||||
|
||||
- [CVE-2026-3592] Limit resolver server list size. ``c3f3879560``
|
||||
|
||||
When resolving a domain with many nameservers that share overlapping
|
||||
IP addresses (e.g., 10 NS records all pointing at the same set of
|
||||
addresses), BIND could previously waste time querying duplicate
|
||||
addresses and build up excessively large server lists. Deduplicate
|
||||
addresses in the resolver's server list so that each unique IP is only
|
||||
queried once per resolution attempt, regardless of how many NS records
|
||||
point to it and cap the number of addresses stored per nameserver name
|
||||
to 6 (combined A and AAAA), preventing memory and CPU overhead from
|
||||
domains with unusually large NS/glue sets. :gl:`#5641`
|
||||
|
||||
- [CVE-2026-3039] Fix GSS-API resource leak. ``92d5c60855``
|
||||
|
||||
Fixed a memory leak where each GSS-API TKEY negotiation leaked a
|
||||
security context inside the GSS library. An unauthenticated attacker
|
||||
could exhaust server memory by sending repeated TKEY queries to a
|
||||
server with tkey-gssapi-keytab configured. The leaked memory was
|
||||
allocated by the GSS library, bypassing BIND's memory accounting.
|
||||
|
||||
Multi-round GSS-API negotiation (GSS_S_CONTINUE_NEEDED) is now
|
||||
rejected, as BIND never supported it correctly and Kerberos/SPNEGO
|
||||
completes in a single round.
|
||||
|
||||
Also implemented missing RFC 3645 requirement: the client now verifies
|
||||
that mutual authentication and integrity flags are granted by the
|
||||
GSS-API mechanism (Section 3.1.1). :gl:`#5752`
|
||||
|
||||
- [CVE-2026-5950] Avoid unbounded recursion loop. ``568be408bc``
|
||||
|
||||
A bug during bad server handling could cause the resolver to enter an
|
||||
infinite loop, continuously sending queries to an upstream server with
|
||||
no exit condition, until the resolver query timeout was hit. This has
|
||||
been fixed.
|
||||
|
||||
ISC would like to thank Billy Baraja (BielraX) for bringing this issue
|
||||
to our attention. :gl:`#5804`
|
||||
|
||||
- [CVE-2026-5947] Fix crash in resolver when SIG(0)-signed responses are
|
||||
received under load. ``9831f41894``
|
||||
|
||||
A resolver could crash when handling a SIG(0)-signed response if the
|
||||
matching client query was cancelled while signature verification was
|
||||
still in progress — for example, when the recursive-clients quota was
|
||||
exhausted. This has been fixed. :gl:`#5819`
|
||||
|
||||
- [CVE-2026-3593] Add system test for HTTP/2 SETTINGS frame flood.
|
||||
``3be272e26d``
|
||||
|
||||
A use-after-free vulnerability in the DNS-over-HTTPS implementation
|
||||
could cause named to crash when a client sends a flood of HTTP/2
|
||||
SETTINGS frames while a DoH response is being written. This affects
|
||||
servers with DoH (DNS-over-HTTPS) enabled.
|
||||
|
||||
ISC would like to thank Naresh Kandula Parmar (Nottiboy) for reporting
|
||||
this.
|
||||
|
||||
For: #5755
|
||||
|
||||
- [CVE-2026-5946] Disable recursion, UPDATE, and NOTIFY for non-IN
|
||||
views. ``014be8be87``
|
||||
|
||||
Recursion, dynamic updates (UPDATE), and zone change notifications
|
||||
(NOTIFY) are now disabled for views with a class other than IN (such
|
||||
as CHAOS or HESIOD); authoritative service for non-IN zones (e.g.
|
||||
version.bind in class CHAOS) continues to work as before. Servers
|
||||
configured with recursion yes in a non-IN view will log a warning at
|
||||
startup, and named-checkconf flags the same condition. UPDATE and
|
||||
NOTIFY messages that specify the meta-classes ANY or NONE in the
|
||||
question section are now rejected with FORMERR.
|
||||
|
||||
This addresses a set of closely related security issues collectively
|
||||
identified as CVE-2026-5946. ISC would like to thank Mcsky23 for
|
||||
bringing these issues to our attention.
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- Remove obsolete KEY record EXTENDED flag deprecated by RFC 3445.
|
||||
``99c226576a``
|
||||
|
||||
KEY resource records originally defined EXTENDED flag that was removed
|
||||
by RFC 3445 back in 2002. BIND still carried code to parse and emit
|
||||
it, including the additional two-octet flags field that followed when
|
||||
the EXTENDED bit was set. That handling has been removed and the
|
||||
affected bit positions are now reserved.
|
||||
|
||||
Dropping the extended-flags handling also eliminates a possible crash
|
||||
that could be reached when signing a zone containing an invalid key.
|
||||
:gl:`#5900`
|
||||
|
||||
Partial backport of MR !11961 :gl:`!11962`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- Revert isdelegation() to return boolean value again. ``6d89bfdf03``
|
||||
|
||||
:gl:`#5838` :gl:`!11802`
|
||||
|
||||
- Fix CPU spikes and slow queries when cache approaches memory limit.
|
||||
``e21ae6358a``
|
||||
|
||||
When the cache grew close to the configured max-cache-size, every
|
||||
subsequent entry triggered all worker threads to run cache cleanup at
|
||||
once, causing CPU spikes and a drop in query throughput. Cleanup is
|
||||
now spread probabilistically across inserts as memory approaches the
|
||||
limit, so the work is distributed evenly instead of piling up at the
|
||||
threshold.
|
||||
|
||||
- Fix off by one error in dnssec-ksr sign. ``819df0d19e``
|
||||
|
||||
If the inception time of the signature is exactly equal to the
|
||||
inactive time of the key, add the signature. :gl:`!11795`
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Check validator name when adding EDE text. ``b6c3390aea``
|
||||
|
||||
When a validator is being shut down, the associated name `val->name`
|
||||
is set to NULL. This could cause a crash if a worker thread
|
||||
subsequently added an EDE code with `val->name` in the extra text.
|
||||
|
||||
`validator_addede()` now checks whether the name is NULL before trying
|
||||
to add it to the extra text. :gl:`#5613` :gl:`!11977`
|
||||
|
||||
- Use the zone file's basename as origin in DNSSEC tools. ``097c14da45``
|
||||
|
||||
In `dnssec-signzone` and `dnssec-verify`, when the zone origin is not
|
||||
specified using the `-o` parameter, the default behavior is to try to
|
||||
sign using the zone's file name as the origin. So, for example,
|
||||
`dnssec-signzone -S example.com` will work, so long as the file name
|
||||
matches the zone name.
|
||||
|
||||
This now also works if the zone is in a different directory. For
|
||||
example, `dnssec-signzone -S zones/example.com` will set the origin
|
||||
value to `example.com`. :gl:`#5678` :gl:`!11784`
|
||||
|
||||
- Fix a possible race condition during zone transfers. ``a48b287d9f``
|
||||
|
||||
The :iscman:`named` process could terminate unexpectedly when
|
||||
processing an IXFR message during a zone transfer. This has been
|
||||
fixed. :gl:`#5767` :gl:`!11799`
|
||||
|
||||
- Make BIND9 compatible with OpenSSL 4. ``8242105d5d``
|
||||
|
||||
OPENSSL_cleanup() in OpenSSL 4 doesn't free the memory, and that is
|
||||
not compatible with BIND 9's memory leak detection code. Don't use
|
||||
custom allocation/deallocation functions for OpenSSL's internal memory
|
||||
management.
|
||||
|
||||
See https://github.com/openssl/openssl/pull/29721 :gl:`#5808`
|
||||
:gl:`!11896`
|
||||
|
||||
- Fix named crash when processing SIG records in dynamic updates.
|
||||
``9e34ef0f7e``
|
||||
|
||||
Previously, :iscman:`named` could abort if a client sent a dynamic
|
||||
update containing a SIG record (the legacy signature type) to a zone
|
||||
configured with an update-policy. The function `dns_db_findrdataset`
|
||||
had an incorrect requirements prerequisite that prevented SIG records
|
||||
being looked up, which was triggered as part of processing an UPDATE
|
||||
request and could be triggered remotely by any client permitted to
|
||||
send updates. This has been fixed by ensuring that SIG records are
|
||||
handled consistently with RRSIG records during update processing.
|
||||
:gl:`#5818` :gl:`!11876`
|
||||
|
||||
- Fix crash in resolver when SIG(0)-signed responses are received under
|
||||
load. ``bbe0b9b8f6``
|
||||
|
||||
A resolver could crash when handling a SIG(0)-signed response if the
|
||||
matching client query was cancelled while signature verification was
|
||||
still in progress — for example, when the recursive-clients quota was
|
||||
exhausted. This has been fixed. :gl:`#5819`
|
||||
|
||||
- Fix zone verification of NSEC3 signed zones. ``de4a9b4fa6``
|
||||
|
||||
Previously, when computing the compressed bitmap during verification
|
||||
of an NSEC3-signed zone, an undersized buffer was used that resulted
|
||||
in an out-of-bounds write if there were too many active windows in the
|
||||
bitmap. This impacted mirror zones which are NSEC3-signed,
|
||||
`dnssec-signzone` and `dnssec-verifyzone`. This has been fixed.
|
||||
:gl:`#5834` :gl:`!11833`
|
||||
|
||||
- Prevent a crash when using both dns64 and filter-aaaa. ``ddcacbc5a8``
|
||||
|
||||
An assertion failure could be triggered if both `dns64` and the
|
||||
`filter-aaaa` plugin were in use simultaneously. This happened if the
|
||||
plugin triggered a second recursion process, which then attempted to
|
||||
store DNS64 state information in a pointer that had already been set
|
||||
by the original recursion process. This has been fixed. :gl:`#5854`
|
||||
:gl:`!11967`
|
||||
|
||||
- Remove unnecessary dns_name_free call. ``35d94fffb0``
|
||||
|
||||
When processing a catalog zone member's primaries definition and there
|
||||
is a TXT record containing an invalid name TSIG key name,
|
||||
dns_name_free was incorrectly called triggering an assertion. This has
|
||||
been fixed. :gl:`#5858` :gl:`!11848`
|
||||
|
||||
- Tidy up the cleanup path in check_signer() ``cf517f73d5``
|
||||
|
||||
When check_signer() processed a DNSKEY whose public-key data could not
|
||||
be parsed, the early return on the parse error skipped the cleanup of
|
||||
the cloned signature rdataset. In every code path that currently
|
||||
reaches this function the cloned rdataset holds no resources, so no
|
||||
memory was actually leaked, but the cleanup is restructured so the
|
||||
parse and the iteration cannot diverge again. :gl:`#5869` :gl:`!11957`
|
||||
|
||||
- Prevent malicious DNSSEC zones from exhausting validator CPU.
|
||||
``c425827743``
|
||||
|
||||
A DNSSEC-signed zone could publish a DNSKEY with an unusually large
|
||||
RSA public exponent and force any validator resolving names in that
|
||||
zone to spend disproportionate CPU verifying signatures. The
|
||||
validator now rejects such DNSKEYs, matching the limit already applied
|
||||
to keys read from files or HSMs. :gl:`#5881` :gl:`!11923`
|
||||
|
||||
- Fix inverted gethostname() check in rndc status. ``5ede4a87eb``
|
||||
|
||||
The replacement of named_os_gethostname() with raw gethostname()
|
||||
inverted the success check: the "localhost" fallback runs on success,
|
||||
and on failure the uninitialized hostname buffer is read by
|
||||
snprintf(), leaking stack memory via the rndc status reply.
|
||||
:gl:`#5889` :gl:`!11881`
|
||||
|
||||
- Fix rndc-confgen aborting on HMAC-SHA-384/512 keys above 512 bits.
|
||||
``7e1eace6cd``
|
||||
|
||||
`rndc-confgen -A hmac-sha384` and `-A hmac-sha512` documented a `-b`
|
||||
range of 1..1024, but any value above 512 aborted on hardened builds
|
||||
instead of producing a key. The full advertised range now works.
|
||||
:gl:`#5903` :gl:`!11910`
|
||||
|
||||
- Prevent crafted queries from degrading RRL performance. ``bf4cdca7e9``
|
||||
|
||||
With response rate limiting enabled, an attacker sending queries from
|
||||
many spoofed source addresses could steer entries into the same slot
|
||||
of the internal rate-limit table and slow down query processing on the
|
||||
affected server. The table now uses a per-process keyed hash so the
|
||||
placement of entries cannot be predicted or influenced from the
|
||||
network. :gl:`#5906` :gl:`!11952`
|
||||
|
||||
- Fix swapped arguments in redirect2() single-label branch.
|
||||
``3728b405ea``
|
||||
|
||||
On a recursive resolver with nxdomain-redirect configured, an NXDOMAIN
|
||||
result for a query whose qname is the root could corrupt the view's
|
||||
nxdomain-redirect target, after which the redirect feature stopped
|
||||
working for every subsequent query in that view until named was
|
||||
restarted. :gl:`#5908` :gl:`!11913`
|
||||
|
||||
- Free per-command rndc state when response serialisation fails.
|
||||
``070b394f53``
|
||||
|
||||
When isccc_cc_towire failed while building an rndc reply,
|
||||
control_respond returned without releasing the per-command request,
|
||||
response, HMAC secret copy, and text buffer. They were eventually
|
||||
freed when the connection closed, but until then the HMAC key copy
|
||||
stayed in named's memory. The failure path now goes through the same
|
||||
cleanup label as every other error. :gl:`#5913` :gl:`!11919`
|
||||
|
||||
- Prevent rare named crash when notifies are cancelled. ``49509dcbae``
|
||||
|
||||
Under heavy load, named could occasionally crash when a queued
|
||||
outbound notify or zone refresh was cancelled at the moment it was
|
||||
being sent — for example, while a zone was being reloaded or removed.
|
||||
The race that caused the crash is now prevented. :gl:`#5915`
|
||||
:gl:`!11922`
|
||||
|
||||
- Stop delv from aborting on a malformed query name. ``ca8315bb4d``
|
||||
|
||||
delv aborts with SIGABRT instead of exiting cleanly when given a query
|
||||
name that fails wire-format conversion (e.g. a label longer than 63
|
||||
octets). After this change delv prints the parse error and exits with
|
||||
a normal failure code. :gl:`#5916` :gl:`!11927`
|
||||
|
||||
- Fix a crash when reconfiguring while an NTA is being rechecked.
|
||||
``971ca4df1a``
|
||||
|
||||
When named was reconfigured or shut down while a negative trust anchor
|
||||
was being rechecked against authoritative servers, the in-flight
|
||||
recheck could outlive the view that owned it and cause `named` to
|
||||
crash. This has been fixed. :gl:`#5938` :gl:`!11966`
|
||||
|
||||
- Fix a bug in allow-query/allow-transfer catalog zone custom
|
||||
properties. ``e962fd459e``
|
||||
|
||||
The :iscman:`named` process could terminate unexpectedly when
|
||||
processing a catalog zone with an invalid ``allow-query`` or
|
||||
``allow-transfer`` custom property (i.e. having a non-APL type)
|
||||
coexisting with the valid property. This has been fixed. :gl:`#5941`
|
||||
:gl:`!11975`
|
||||
|
||||
- Fix a stack use-after-free in qpzone. ``ddea991c07``
|
||||
|
||||
In previous_closest_nsec(), a new qpreader was opened to search the
|
||||
NSEC tree. It was possible for that to be used to update a QP iterator
|
||||
object owned by the caller, and then be destroyed when the function
|
||||
returned.
|
||||
|
||||
This has been addressed by having the caller open the NSEC qpreader
|
||||
instead. :gl:`#5942` :gl:`!11956`
|
||||
|
||||
- Fix a memory leak issue in the catalog zones. ``5fcb6d8809``
|
||||
|
||||
The :iscman:`named` process could leak small amounts of memory when
|
||||
processing a catalog zone entry which had defined custom primary
|
||||
servers with TSIG keys using both the regular ``primaries`` custom
|
||||
property syntax and the legacy alternative syntax (``masters``) at the
|
||||
same time. This has been fixed. :gl:`#5943` :gl:`!11973`
|
||||
|
||||
- Fix suppressed missing-glue check in named-checkzone. ``dc5eb3fe25``
|
||||
|
||||
named-checkzone and named-checkconf -z silently skipped the
|
||||
missing-glue check for any NS name that had already triggered an
|
||||
extra-AAAA-glue warning, so zones missing required A glue could pass
|
||||
validation and be deployed with broken delegations. :gl:`!11905`
|
||||
|
||||
- Implement seamless outgoing TCP connection reuse. ``eb117e16b9``
|
||||
|
||||
The resolver can and will reuse outgoing TCP connections to the same
|
||||
host, as recommended by RFC 7766. This prevents a whole class of
|
||||
attacks that abuse the fact that establishing a TCP connection is
|
||||
expensive and it is fairly easy to deplete the outgoing TCP ports by
|
||||
putting them into TIME_WAIT state.
|
||||
|
||||
The number of pipelined queries per connection is capped at 256 to
|
||||
limit the impact of a connection drop. :gl:`!11846`
|
||||
|
||||
- Pass empty string instead of NULL to ns_client_dumpmessage()
|
||||
``24cdf8c096``
|
||||
|
||||
Pass "" instead of NULL to ns_client_dumpmessage() to get the log
|
||||
message printed.
|
||||
|
||||
- Reject record sets too large to serve in DNS. ``933a8de056``
|
||||
|
||||
When BIND was asked to store a record set whose total size exceeds
|
||||
what fits in a DNS message, it would allocate memory and build the
|
||||
structure, then fail later at response time. Such oversized record
|
||||
sets are now rejected at the time of storage with an error, avoiding
|
||||
wasted work on data that can never be served. :gl:`!11964`
|
||||
|
||||
|
||||
264
doc/notes/notes-9.20.23.rst
Normal file
264
doc/notes/notes-9.20.23.rst
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
.. 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.20.23
|
||||
----------------------
|
||||
|
||||
Security Fixes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- Limit resolver server list size. :cve:`2026-3592`
|
||||
|
||||
When resolving a domain with many nameservers that shared overlapping
|
||||
IP addresses (e.g., 10 NS records all pointing at the same set of
|
||||
addresses), BIND could previously waste time querying duplicate
|
||||
addresses and build up excessively large server lists. Addresses in
|
||||
the resolver's server list are now deduplicated so that each unique IP is only
|
||||
queried once per resolution attempt, regardless of how many NS records
|
||||
point to it. The number of addresses stored per nameserver name
|
||||
is also now capped at six (combined A and AAAA), preventing memory and CPU overhead from
|
||||
domains with unusually large NS/glue sets.
|
||||
|
||||
ISC would like to thank Shuhan Zhang from Tsinghua University for
|
||||
reporting this issue. :gl:`#5641`
|
||||
|
||||
- Fix GSS-API resource leak. :cve:`2026-3039`
|
||||
|
||||
A memory leak was fixed where each GSS-API TKEY negotiation leaked a
|
||||
security context inside the GSS library. An unauthenticated attacker
|
||||
could exhaust server memory by sending repeated TKEY queries to a
|
||||
server with :any:`tkey-gssapi-keytab` configured. The leaked memory was
|
||||
allocated by the GSS library, bypassing BIND's memory accounting.
|
||||
|
||||
Multi-round GSS-API negotiation (GSS_S_CONTINUE_NEEDED) is now
|
||||
rejected, as BIND never supported it correctly and Kerberos/SPNEGO
|
||||
completes in a single round.
|
||||
|
||||
ISC would like to thank Vitaly Simonovich for bringing this
|
||||
vulnerability to our attention. :gl:`#5752`
|
||||
|
||||
- Disable recursion, UPDATE, and NOTIFY for non-IN views.
|
||||
:cve:`2026-5946`
|
||||
|
||||
Recursion, dynamic updates (UPDATE), and zone change notifications
|
||||
(NOTIFY) are now disabled for views with a class other than IN (such
|
||||
as CHAOS or HESIOD); authoritative service for non-IN zones (e.g.
|
||||
version.bind in class CHAOS) continues to work as before. Servers
|
||||
configured with :namedconf:ref:`recursion yes; <recursion>`
|
||||
in a non-IN view log a warning at
|
||||
startup, and :iscman:`named-checkconf` flags the same condition. UPDATE and
|
||||
NOTIFY messages that specify the meta-classes ANY or NONE in the
|
||||
question section are now rejected with FORMERR.
|
||||
|
||||
This addresses a set of closely related security issues collectively
|
||||
identified as CVE-2026-5946. ISC would like to thank Mcsky23 for
|
||||
bringing these issues to our attention. :gl:`#5784`
|
||||
|
||||
- Avoid unbounded recursion loop. :cve:`2026-5950`
|
||||
|
||||
A bug during bad server handling could cause the resolver to enter an
|
||||
infinite loop, continuously sending queries to an upstream server with
|
||||
no exit condition, until the resolver query timeout was hit. This has
|
||||
been fixed.
|
||||
|
||||
ISC would like to thank Billy Baraja (BielraX) for bringing this issue
|
||||
to our attention. :gl:`#5804`
|
||||
|
||||
- Fix crash in resolver when SIG(0)-signed responses are received under
|
||||
load. :cve:`2026-5947`
|
||||
|
||||
A resolver could crash when handling a SIG(0)-signed response if the
|
||||
matching client query was cancelled while signature verification was
|
||||
still in progress — for example, when the recursive-clients quota was
|
||||
exhausted. This has been fixed.
|
||||
|
||||
ISC would like to thank Naoki Wakamatsu for bringing this
|
||||
vulnerability to our attention. :gl:`#5819`
|
||||
|
||||
- Fix use-after-free error in DNS-over-HTTPS when processing HTTP/2
|
||||
SETTINGS frames. :cve:`2026-3593`
|
||||
|
||||
Previously, a use-after-free vulnerability in the DNS-over-HTTPS implementation
|
||||
could cause :iscman:`named` to crash when a client sent a flood of HTTP/2
|
||||
SETTINGS frames while a DoH response was being written. This affected
|
||||
servers with DoH (DNS-over-HTTPS) enabled and has been fixed.
|
||||
|
||||
ISC would like to thank Naresh Kandula Parmar (Nottiboy) for reporting
|
||||
this. :gl:`#5755`
|
||||
|
||||
- Fix outgoing zone transfers' quota issue.
|
||||
|
||||
Unauthorized clients could consume the entire outgoing zone-transfer quota and
|
||||
block authorized zone transfer clients. This has been fixed.
|
||||
:gl:`#3589`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- Fix CPU spikes and slow queries when cache approaches memory limit.
|
||||
|
||||
Cache cleanup is now spread probabilistically to avoid CPU usage spikes and a
|
||||
drop in query throughput. :gl:`#5891`
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- Use the zone file's basename as origin in DNSSEC tools.
|
||||
|
||||
In :iscman:`dnssec-signzone` and :iscman:`dnssec-verify`, when the zone origin is not
|
||||
specified using the ``-o`` parameter, the default behavior is to try to
|
||||
sign using the zone's file name as the origin. So, for example,
|
||||
``dnssec-signzone -S example.com`` will work, so long as the file name
|
||||
matches the zone name.
|
||||
|
||||
This now also works if the zone is in a different directory. For
|
||||
example, ``dnssec-signzone -S zones/example.com`` will set the origin
|
||||
value to ``example.com``. :gl:`#5678`
|
||||
|
||||
- Fix a possible race condition during zone transfers.
|
||||
|
||||
The :iscman:`named` process could terminate unexpectedly when
|
||||
processing an IXFR message during a zone transfer. This has been
|
||||
fixed. :gl:`#5767`
|
||||
|
||||
- Fix :iscman:`named` crash when processing SIG records in dynamic updates.
|
||||
|
||||
Previously, :iscman:`named` could abort if a client sent a dynamic
|
||||
update containing a SIG record (the legacy signature type) to a zone
|
||||
configured with an update-policy. The function `dns_db_findrdataset`
|
||||
had an incorrect requirements prerequisite that prevented SIG records
|
||||
from being looked up, which was triggered as part of processing an UPDATE
|
||||
request and could be triggered remotely by any client permitted to
|
||||
send updates. This has been fixed by ensuring that SIG records are
|
||||
handled consistently with RRSIG records during update processing.
|
||||
:gl:`#5818`
|
||||
|
||||
- Fix :option:`rndc modzone` behavior for a zone in named.conf.
|
||||
|
||||
If a zone was present in the configuration file and not originally
|
||||
added by :option:`rndc addzone`, :option:`rndc modzone` for that zone would succeed
|
||||
once but subsequent :option:`rndc modzone` attempts would fail. This has been
|
||||
fixed. :gl:`#5826`
|
||||
|
||||
- Fix zone verification of NSEC3 signed zones.
|
||||
|
||||
Previously, when computing the compressed bitmap during verification
|
||||
of an NSEC3-signed zone, an undersized buffer was used that resulted
|
||||
in an out-of-bounds write if there were too many active windows in the
|
||||
bitmap. This impacted the mirror zones which are NSEC3-signed,
|
||||
:iscman:`dnssec-signzone` and :iscman:`dnssec-verify`. This has been fixed.
|
||||
:gl:`#5834`
|
||||
|
||||
- Prevent a crash when using both :any:`dns64` and :any:`filter-aaaa`.
|
||||
|
||||
An assertion failure could be triggered if both :any:`dns64` and the
|
||||
:any:`filter-aaaa` plugin were in use simultaneously. This happened if the
|
||||
plugin triggered a second recursion process, which then attempted to
|
||||
store DNS64 state information in a pointer that had already been set
|
||||
by the original recursion process. This has been fixed. :gl:`#5854`
|
||||
|
||||
- Fixed an assertion failure when processing catalog zones.
|
||||
|
||||
If a TXT record containing an invalid name TSIG key name was found
|
||||
when processing a catalog zone member's primaries definition,
|
||||
``dns_name_free`` was incorrectly called, triggering an assertion. This has
|
||||
been fixed. :gl:`#5858`
|
||||
|
||||
- Prevent malicious DNSSEC zones from exhausting validator CPU.
|
||||
|
||||
A DNSSEC-signed zone could publish a DNSKEY with an unusually large
|
||||
RSA public exponent and force any validator resolving names in that
|
||||
zone to spend disproportionate CPU verifying signatures. The
|
||||
validator now rejects such DNSKEYs, matching the limit already applied
|
||||
to keys read from files or HSMs. :gl:`#5881`
|
||||
|
||||
- Fix :iscman:`rndc-confgen` aborting on HMAC-SHA-384/512 keys above 512 bits.
|
||||
|
||||
:iscman:`rndc-confgen` (with either ``-A hmac-sha384`` or
|
||||
``-A hmac-sha512``) previously documented a ``-b``
|
||||
range of 1..1024, but any value above 512 aborted on hardened builds
|
||||
instead of producing a key. The full advertised range now works.
|
||||
:gl:`#5903`
|
||||
|
||||
- Prevent crafted queries from degrading RRL performance.
|
||||
|
||||
With response rate limiting enabled, an attacker sending queries from
|
||||
many spoofed source addresses could steer entries into the same slot
|
||||
of the internal rate-limit table and slow down query processing on the
|
||||
affected server. The table now uses a per-process keyed hash so the
|
||||
placement of entries cannot be predicted or influenced from the
|
||||
network. :gl:`#5906`
|
||||
|
||||
- Prevent rare :iscman:`named` crash when notifies are cancelled.
|
||||
|
||||
Under heavy load, :iscman:`named` could occasionally crash when a queued
|
||||
outbound notify or zone refresh was cancelled at the moment it was
|
||||
being sent — for example, while a zone was being reloaded or removed.
|
||||
The race that caused the crash is now prevented. :gl:`#5915`
|
||||
|
||||
- Stop :iscman:`delv` from aborting on a malformed query name.
|
||||
|
||||
:iscman:`delv` previously aborted with SIGABRT instead of exiting cleanly when given a query
|
||||
name that failed wire-format conversion (e.g. a label longer than 63
|
||||
octets). After this change :iscman:`delv` prints the parse error and exits with
|
||||
a normal failure code. :gl:`#5916`
|
||||
|
||||
- Fix a crash when reconfiguring while an NTA is being rechecked.
|
||||
|
||||
Previously, if :iscman:`named` was reconfigured or shut down while a negative trust anchor
|
||||
was being rechecked against authoritative servers, the in-flight
|
||||
recheck could outlive the view that owned it and cause :iscman:`named` to
|
||||
crash. This has been fixed. :gl:`#5938`
|
||||
|
||||
- Fix a bug in :any:`allow-query`/:any:`allow-transfer` catalog zone custom
|
||||
properties.
|
||||
|
||||
The :iscman:`named` process could terminate unexpectedly when
|
||||
processing a catalog zone with an invalid :any:`allow-query` or
|
||||
:any:`allow-transfer` custom property (i.e. having a non-APL type)
|
||||
coexisting with the valid property. This has been fixed. :gl:`#5941`
|
||||
|
||||
- Fix a memory leak issue in catalog zones.
|
||||
|
||||
The :iscman:`named` process could leak small amounts of memory when
|
||||
processing a catalog zone entry which had defined custom primary
|
||||
servers with TSIG keys, if both the regular ``primaries`` custom
|
||||
property syntax and the legacy alternative syntax (``masters``) were used at the
|
||||
same time. This has been fixed. :gl:`#5943`
|
||||
|
||||
- Fix suppressed missing-glue check in :iscman:`named-checkzone`.
|
||||
|
||||
:iscman:`named-checkzone` and :option:`named-checkconf -z` silently
|
||||
skipped the missing-glue check for any NS name that had already
|
||||
triggered an extra-AAAA-glue warning, so zones missing required A glue
|
||||
could pass validation and be deployed with broken delegations.
|
||||
:gl:`!11899`
|
||||
|
||||
- Implement seamless outgoing TCP connection reuse.
|
||||
|
||||
The resolver can and will reuse outgoing TCP connections to the same
|
||||
host, as recommended by :rfc:`7766`. This prevents a whole class of
|
||||
attacks that abuse the fact that establishing a TCP connection is
|
||||
expensive and it is fairly easy to deplete the outgoing TCP ports by
|
||||
putting them into ``TIME_WAIT`` state.
|
||||
|
||||
The number of pipelined queries per connection is capped at 256 to
|
||||
limit the impact of a connection drop. :gl:`!11845`
|
||||
|
||||
- Reject record sets too large to serve in DNS.
|
||||
|
||||
When BIND was asked to store a record set whose total size exceeded
|
||||
what fit in a DNS message, it would allocate memory and build the
|
||||
structure, then fail later at response time. Such oversized record
|
||||
sets are now rejected at the time of storage with an error, avoiding
|
||||
wasted work on data that can never be served. :gl:`!11963`
|
||||
|
||||
|
||||
|
|
@ -78,6 +78,15 @@
|
|||
|
||||
#define DNS_ADB_MINADBSIZE (1024U * 1024U) /*%< 1 Megabyte */
|
||||
|
||||
/*
|
||||
* Default and override for the per-find address limit, the sum of the number of
|
||||
* A and AAAA RR from an ADB NS name resolution. When non-zero, this value is
|
||||
* used instead of the default. Can be set via 'named -T adbaddrslimit=N' for
|
||||
* testing.
|
||||
*/
|
||||
#define DEFAULT_ADDRSLIMIT 6
|
||||
size_t dns_adb_addrslimit = 0;
|
||||
|
||||
typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
|
||||
typedef struct dns_adbnamehook dns_adbnamehook_t;
|
||||
typedef ISC_LIST(dns_adbnamehook_t) dns_adbnamehooklist_t;
|
||||
|
|
@ -558,6 +567,9 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
|||
|
||||
rdtype = rdataset->type;
|
||||
|
||||
REQUIRE(rdataset->rdclass == dns_rdataclass_in);
|
||||
REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
|
||||
|
||||
switch (rdataset->trust) {
|
||||
case dns_trust_glue:
|
||||
case dns_trust_additional:
|
||||
|
|
@ -570,8 +582,6 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
|||
rdataset->ttl = ttlclamp(rdataset->ttl);
|
||||
}
|
||||
|
||||
REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
|
||||
|
||||
for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(rdataset))
|
||||
{
|
||||
|
|
@ -1473,6 +1483,9 @@ static void
|
|||
copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
|
||||
dns_adbnamehook_t *namehook = NULL;
|
||||
dns_adbentry_t *entry = NULL;
|
||||
size_t count = 0;
|
||||
size_t limit = dns_adb_addrslimit != 0 ? dns_adb_addrslimit
|
||||
: DEFAULT_ADDRSLIMIT;
|
||||
|
||||
if ((find->options & DNS_ADBFIND_INET) != 0) {
|
||||
namehook = ISC_LIST_HEAD(name->v4);
|
||||
|
|
@ -1493,6 +1506,12 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
|
|||
* Found a valid entry. Add it to the find's list.
|
||||
*/
|
||||
ISC_LIST_APPEND(find->list, addrinfo, publink);
|
||||
|
||||
if (++count >= limit) {
|
||||
DP(ISC_LOG_DEBUG(3), "skipping addresses");
|
||||
return;
|
||||
}
|
||||
|
||||
nextv4:
|
||||
namehook = ISC_LIST_NEXT(namehook, name_link);
|
||||
}
|
||||
|
|
@ -1517,6 +1536,12 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_adbname_t *name) {
|
|||
* Found a valid entry. Add it to the find's list.
|
||||
*/
|
||||
ISC_LIST_APPEND(find->list, addrinfo, publink);
|
||||
|
||||
if (++count >= limit) {
|
||||
DP(ISC_LOG_DEBUG(3), "skipping addresses");
|
||||
return;
|
||||
}
|
||||
|
||||
nextv6:
|
||||
namehook = ISC_LIST_NEXT(namehook, name_link);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -607,7 +607,14 @@ dst_gssapi_initctx(const dns_name_t *name, isc_buffer_t *intoken,
|
|||
GSS_SPNEGO_MECHANISM, flags, 0, NULL, gintokenp, NULL,
|
||||
&gouttoken, &ret_flags, NULL);
|
||||
|
||||
if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) {
|
||||
switch (gret) {
|
||||
case GSS_S_COMPLETE:
|
||||
result = ISC_R_SUCCESS;
|
||||
break;
|
||||
case GSS_S_CONTINUE_NEEDED:
|
||||
result = DNS_R_CONTINUE;
|
||||
break;
|
||||
default:
|
||||
gss_err_message(mctx, gret, minor, err_message);
|
||||
if (err_message != NULL && *err_message != NULL) {
|
||||
gss_log(3, "Failure initiating security context: %s",
|
||||
|
|
@ -632,12 +639,6 @@ dst_gssapi_initctx(const dns_name_t *name, isc_buffer_t *intoken,
|
|||
CHECK(isc_buffer_copyregion(outtoken, &r));
|
||||
}
|
||||
|
||||
if (gret == GSS_S_COMPLETE) {
|
||||
result = ISC_R_SUCCESS;
|
||||
} else {
|
||||
result = DNS_R_CONTINUE;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (gouttoken.length != 0U) {
|
||||
(void)gss_release_buffer(&minor, &gouttoken);
|
||||
|
|
@ -648,7 +649,7 @@ cleanup:
|
|||
|
||||
isc_result_t
|
||||
dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab,
|
||||
isc_region_t *intoken, isc_buffer_t **outtoken,
|
||||
isc_region_t *intoken, isc_buffer_t **outtokenp,
|
||||
dns_gss_ctx_id_t *ctxout, dns_name_t *principal,
|
||||
isc_mem_t *mctx) {
|
||||
isc_region_t r;
|
||||
|
|
@ -661,16 +662,11 @@ dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab,
|
|||
isc_result_t result;
|
||||
char buf[1024];
|
||||
|
||||
REQUIRE(outtoken != NULL && *outtoken == NULL);
|
||||
REQUIRE(outtokenp != NULL && *outtokenp == NULL);
|
||||
REQUIRE(*ctxout == NULL);
|
||||
|
||||
REGION_TO_GBUFFER(*intoken, gintoken);
|
||||
|
||||
if (*ctxout == NULL) {
|
||||
context = GSS_C_NO_CONTEXT;
|
||||
} else {
|
||||
context = *ctxout;
|
||||
}
|
||||
|
||||
if (gssapi_keytab != NULL) {
|
||||
#if HAVE_GSSAPI_GSSAPI_KRB5_H || HAVE_GSSAPI_KRB5_H
|
||||
gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
|
||||
|
|
@ -715,8 +711,15 @@ dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab,
|
|||
|
||||
switch (gret) {
|
||||
case GSS_S_COMPLETE:
|
||||
case GSS_S_CONTINUE_NEEDED:
|
||||
break;
|
||||
/*
|
||||
* RFC 3645 4.1.3: we don't handle GSS_S_CONTINUE_NEEDED
|
||||
* Multi-round GSS-API negotiation is not supported.
|
||||
*/
|
||||
case GSS_S_CONTINUE_NEEDED:
|
||||
gss_log(3, "multi-round GSS-API negotiation not supported");
|
||||
(void)gss_delete_sec_context(&minor, &context, NULL);
|
||||
FALLTHROUGH;
|
||||
case GSS_S_DEFECTIVE_TOKEN:
|
||||
case GSS_S_DEFECTIVE_CREDENTIAL:
|
||||
case GSS_S_BAD_SIG:
|
||||
|
|
@ -729,7 +732,7 @@ dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab,
|
|||
case GSS_S_BAD_MECH:
|
||||
case GSS_S_FAILURE:
|
||||
result = DNS_R_INVALIDTKEY;
|
||||
/* fall through */
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
gss_log(3, "failed gss_accept_sec_context: %s",
|
||||
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
||||
|
|
@ -740,50 +743,55 @@ dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab,
|
|||
}
|
||||
|
||||
if (gouttoken.length > 0U) {
|
||||
isc_buffer_allocate(mctx, outtoken,
|
||||
isc_buffer_allocate(mctx, outtokenp,
|
||||
(unsigned int)gouttoken.length);
|
||||
GBUFFER_TO_REGION(gouttoken, r);
|
||||
CHECK(isc_buffer_copyregion(*outtoken, &r));
|
||||
CHECK(isc_buffer_copyregion(*outtokenp, &r));
|
||||
(void)gss_release_buffer(&minor, &gouttoken);
|
||||
}
|
||||
|
||||
if (gret == GSS_S_COMPLETE) {
|
||||
gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
|
||||
if (gret != GSS_S_COMPLETE) {
|
||||
gss_log(3, "failed gss_display_name: %s",
|
||||
gss_error_tostring(gret, minor, buf,
|
||||
sizeof(buf)));
|
||||
CHECK(ISC_R_FAILURE);
|
||||
}
|
||||
INSIST(gret == GSS_S_COMPLETE);
|
||||
|
||||
/*
|
||||
* Compensate for a bug in Solaris8's implementation
|
||||
* of gss_display_name(). Should be harmless in any
|
||||
* case, since principal names really should not
|
||||
* contain null characters.
|
||||
*/
|
||||
if (gnamebuf.length > 0U &&
|
||||
((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
|
||||
{
|
||||
gnamebuf.length--;
|
||||
}
|
||||
|
||||
gss_log(3, "gss-api source name (accept) is %.*s",
|
||||
(int)gnamebuf.length, (char *)gnamebuf.value);
|
||||
|
||||
GBUFFER_TO_REGION(gnamebuf, r);
|
||||
isc_buffer_init(&namebuf, r.base, r.length);
|
||||
isc_buffer_add(&namebuf, r.length);
|
||||
|
||||
CHECK(dns_name_fromtext(principal, &namebuf, dns_rootname, 0,
|
||||
NULL));
|
||||
} else {
|
||||
result = DNS_R_CONTINUE;
|
||||
gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
|
||||
if (gret != GSS_S_COMPLETE) {
|
||||
gss_log(3, "failed gss_display_name: %s",
|
||||
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compensate for a bug in Solaris8's implementation
|
||||
* of gss_display_name(). Should be harmless in any
|
||||
* case, since principal names really should not
|
||||
* contain null characters.
|
||||
*/
|
||||
if (gnamebuf.length > 0U &&
|
||||
((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
|
||||
{
|
||||
gnamebuf.length--;
|
||||
}
|
||||
|
||||
gss_log(3, "gss-api source name (accept) is %.*s", (int)gnamebuf.length,
|
||||
(char *)gnamebuf.value);
|
||||
|
||||
GBUFFER_TO_REGION(gnamebuf, r);
|
||||
isc_buffer_init(&namebuf, r.base, r.length);
|
||||
isc_buffer_add(&namebuf, r.length);
|
||||
|
||||
CHECK(dns_name_fromtext(principal, &namebuf, dns_rootname, 0, NULL));
|
||||
|
||||
*ctxout = context;
|
||||
|
||||
cleanup:
|
||||
if (result != ISC_R_SUCCESS && *outtokenp != NULL) {
|
||||
isc_buffer_free(outtokenp);
|
||||
}
|
||||
|
||||
if (result != ISC_R_SUCCESS && context != GSS_C_NO_CONTEXT) {
|
||||
(void)gss_delete_sec_context(&minor, &context, NULL);
|
||||
}
|
||||
|
||||
if (gnamebuf.length != 0U) {
|
||||
gret = gss_release_buffer(&minor, &gnamebuf);
|
||||
if (gret != GSS_S_COMPLETE) {
|
||||
|
|
|
|||
|
|
@ -113,20 +113,17 @@ dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab,
|
|||
* generated by gss_accept_sec_context() to be sent to the
|
||||
* initiator
|
||||
* 'context' is a valid pointer to receive the generated context handle.
|
||||
* On the initial call, it should be a pointer to NULL, which
|
||||
* will be allocated as a dns_gss_ctx_id_t. Subsequent calls
|
||||
* should pass in the handle generated on the first call.
|
||||
* Call dst_gssapi_releasecred to delete the context and free
|
||||
* the memory.
|
||||
*
|
||||
* Requires:
|
||||
* 'outtoken' to != NULL && *outtoken == NULL.
|
||||
* 'outtoken' != NULL && *outtoken == NULL.
|
||||
* 'context' != NULL && *context == NULL.
|
||||
*
|
||||
* Returns:
|
||||
* ISC_R_SUCCESS msg was successfully updated to include the
|
||||
* query to be sent
|
||||
* DNS_R_CONTINUE transaction still in progress
|
||||
* other an error occurred while building the message
|
||||
* ISC_R_SUCCESS msg was successfully updated to include
|
||||
* the query to be sent
|
||||
* DNS_R_INVALIDTKEY an error occurred while accepting the
|
||||
* context
|
||||
* ISC_R_FAILURE other error occurred
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
|
|
|
|||
|
|
@ -1073,6 +1073,17 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
rdtype = isc_buffer_getuint16(source);
|
||||
rdclass = isc_buffer_getuint16(source);
|
||||
|
||||
/*
|
||||
* Notify and update messages need to specify the data class.
|
||||
*/
|
||||
if ((msg->opcode == dns_opcode_update ||
|
||||
msg->opcode == dns_opcode_notify) &&
|
||||
(rdclass == dns_rdataclass_none ||
|
||||
rdclass == dns_rdataclass_any))
|
||||
{
|
||||
DO_ERROR(DNS_R_FORMERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this class is different than the one we already read,
|
||||
* this is an error.
|
||||
|
|
|
|||
|
|
@ -383,7 +383,16 @@ struct fetchctx {
|
|||
dns_message_t *qmessage;
|
||||
ISC_LIST(resquery_t) queries;
|
||||
dns_adbfindlist_t finds;
|
||||
dns_adbfind_t *find;
|
||||
/*
|
||||
* This is a state to keep track of the latest upstream server which is
|
||||
* being queried. See `nextaddress()`.
|
||||
*
|
||||
* `addrinfo` is basically a copy of `foundaddrinfo` but came from the
|
||||
* response of the query, so fields like the SRTT/timing might have been
|
||||
* altered. So it might be possible (?) to wrap those two in an union
|
||||
* for clarity (and memory saving).
|
||||
*/
|
||||
dns_adbaddrinfo_t *foundaddrinfo;
|
||||
/*
|
||||
* altfinds are names and/or addresses of dual stack servers that
|
||||
* should be used when iterative resolution to a server is not
|
||||
|
|
@ -1323,7 +1332,7 @@ fctx_cleanup(fetchctx_t *fctx) {
|
|||
dns_adb_destroyfind(&find);
|
||||
fetchctx_unref(fctx);
|
||||
}
|
||||
fctx->find = NULL;
|
||||
fctx->foundaddrinfo = NULL;
|
||||
|
||||
for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL;
|
||||
find = next_find)
|
||||
|
|
@ -3156,89 +3165,6 @@ add_bad(fetchctx_t *fctx, dns_message_t *rmessage, dns_adbaddrinfo_t *addrinfo,
|
|||
isc_result_totext(reason), namebuf, typebuf, classbuf, addrbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort addrinfo list by RTT.
|
||||
*/
|
||||
static void
|
||||
sort_adbfind(dns_adbfind_t *find, unsigned int bias) {
|
||||
dns_adbaddrinfo_t *best, *curr;
|
||||
dns_adbaddrinfolist_t sorted;
|
||||
|
||||
/* Lame N^2 bubble sort. */
|
||||
ISC_LIST_INIT(sorted);
|
||||
while (!ISC_LIST_EMPTY(find->list)) {
|
||||
unsigned int best_srtt;
|
||||
best = ISC_LIST_HEAD(find->list);
|
||||
best_srtt = best->srtt;
|
||||
if (isc_sockaddr_pf(&best->sockaddr) != AF_INET6) {
|
||||
best_srtt += bias;
|
||||
}
|
||||
curr = ISC_LIST_NEXT(best, publink);
|
||||
while (curr != NULL) {
|
||||
unsigned int curr_srtt = curr->srtt;
|
||||
if (isc_sockaddr_pf(&curr->sockaddr) != AF_INET6) {
|
||||
curr_srtt += bias;
|
||||
}
|
||||
if (curr_srtt < best_srtt) {
|
||||
best = curr;
|
||||
best_srtt = curr_srtt;
|
||||
}
|
||||
curr = ISC_LIST_NEXT(curr, publink);
|
||||
}
|
||||
ISC_LIST_UNLINK(find->list, best, publink);
|
||||
ISC_LIST_APPEND(sorted, best, publink);
|
||||
}
|
||||
find->list = sorted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort a list of finds by server RTT.
|
||||
*/
|
||||
static void
|
||||
sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) {
|
||||
dns_adbfind_t *best, *curr;
|
||||
dns_adbfindlist_t sorted;
|
||||
dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
|
||||
|
||||
/* Sort each find's addrinfo list by SRTT. */
|
||||
for (curr = ISC_LIST_HEAD(*findlist); curr != NULL;
|
||||
curr = ISC_LIST_NEXT(curr, publink))
|
||||
{
|
||||
sort_adbfind(curr, bias);
|
||||
}
|
||||
|
||||
/* Lame N^2 bubble sort. */
|
||||
ISC_LIST_INIT(sorted);
|
||||
while (!ISC_LIST_EMPTY(*findlist)) {
|
||||
unsigned int best_srtt;
|
||||
best = ISC_LIST_HEAD(*findlist);
|
||||
bestaddrinfo = ISC_LIST_HEAD(best->list);
|
||||
INSIST(bestaddrinfo != NULL);
|
||||
best_srtt = bestaddrinfo->srtt;
|
||||
if (isc_sockaddr_pf(&bestaddrinfo->sockaddr) != AF_INET6) {
|
||||
best_srtt += bias;
|
||||
}
|
||||
curr = ISC_LIST_NEXT(best, publink);
|
||||
while (curr != NULL) {
|
||||
unsigned int curr_srtt;
|
||||
addrinfo = ISC_LIST_HEAD(curr->list);
|
||||
INSIST(addrinfo != NULL);
|
||||
curr_srtt = addrinfo->srtt;
|
||||
if (isc_sockaddr_pf(&addrinfo->sockaddr) != AF_INET6) {
|
||||
curr_srtt += bias;
|
||||
}
|
||||
if (curr_srtt < best_srtt) {
|
||||
best = curr;
|
||||
best_srtt = curr_srtt;
|
||||
}
|
||||
curr = ISC_LIST_NEXT(curr, publink);
|
||||
}
|
||||
ISC_LIST_UNLINK(*findlist, best, publink);
|
||||
ISC_LIST_APPEND(sorted, best, publink);
|
||||
}
|
||||
*findlist = sorted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true iff the ADB find has an already pending fetch for 'type'. This
|
||||
* is used to find out whether we're in a loop, where a fetch is waiting for a
|
||||
|
|
@ -3359,6 +3285,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & FCTX_ADDRINFO_DUALSTACK) != 0) {
|
||||
ISC_LIST_APPEND(fctx->altfinds, find, publink);
|
||||
} else {
|
||||
|
|
@ -3833,8 +3760,6 @@ out:
|
|||
* We've found some addresses. We might still be
|
||||
* looking for more addresses.
|
||||
*/
|
||||
sort_finds(&fctx->finds, res->view->v6bias);
|
||||
sort_finds(&fctx->altfinds, 0);
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -3906,6 +3831,80 @@ possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr) {
|
|||
}
|
||||
}
|
||||
|
||||
static dns_adbaddrinfo_t *
|
||||
nextaddress(fetchctx_t *fctx) {
|
||||
dns_adbaddrinfo_t *prevai = fctx->foundaddrinfo, *lowestsrttai = NULL;
|
||||
unsigned int v6bias = fctx->res->view->v6bias, lowestsrtt = 0;
|
||||
|
||||
/*
|
||||
* Let's walk through the list of dns_adbaddrinfo_t to find the best
|
||||
* next server address to query. This is linear on the number of
|
||||
* dns_adbaddrinfo_t which are grouped in find list (for each ADB find).
|
||||
*/
|
||||
for (dns_adbfind_t *find = ISC_LIST_HEAD(fctx->finds); find != NULL;
|
||||
find = ISC_LIST_NEXT(find, publink))
|
||||
{
|
||||
for (dns_adbaddrinfo_t *ai = ISC_LIST_HEAD(find->list);
|
||||
ai != NULL; ai = ISC_LIST_NEXT(ai, publink))
|
||||
{
|
||||
/*
|
||||
* This address has been marked already, skip it.
|
||||
*/
|
||||
if (!UNMARKED(ai)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This address is the same as the previously used
|
||||
* address, it's a duplicate, mark it and skip it!
|
||||
*/
|
||||
if (prevai != NULL) {
|
||||
if (prevai->entry == ai->entry) {
|
||||
ai->flags |= FCTX_ADDRINFO_MARK;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark and skip this address if incompatible (i.e. IPv6
|
||||
* address on a v4 only server, or for ACL reason, etc.)
|
||||
*/
|
||||
possibly_mark(fctx, ai);
|
||||
if (!UNMARKED(ai)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* This address hasn't been tried yet and is a
|
||||
* good candidate. Let's keep track of it if it
|
||||
* has the lowest SRTT so far (or if there is no
|
||||
* address with lowest SRTT found yet).
|
||||
*/
|
||||
unsigned int aisrtt = ai->srtt;
|
||||
|
||||
if (isc_sockaddr_pf(&ai->sockaddr) != AF_INET6) {
|
||||
aisrtt += v6bias;
|
||||
}
|
||||
|
||||
if (lowestsrttai == NULL || aisrtt < lowestsrtt) {
|
||||
lowestsrttai = ai;
|
||||
lowestsrtt = aisrtt;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the next address to query. If this is NULL, we're done.
|
||||
*/
|
||||
if (lowestsrttai != NULL) {
|
||||
lowestsrttai->flags |= FCTX_ADDRINFO_MARK;
|
||||
}
|
||||
fctx->foundaddrinfo = lowestsrttai;
|
||||
|
||||
return lowestsrttai;
|
||||
}
|
||||
|
||||
static dns_adbaddrinfo_t *
|
||||
fctx_nextaddress(fetchctx_t *fctx) {
|
||||
dns_adbfind_t *find, *start;
|
||||
|
|
@ -3928,7 +3927,6 @@ fctx_nextaddress(fetchctx_t *fctx) {
|
|||
possibly_mark(fctx, addrinfo);
|
||||
if (UNMARKED(addrinfo)) {
|
||||
addrinfo->flags |= FCTX_ADDRINFO_MARK;
|
||||
fctx->find = NULL;
|
||||
fctx->forwarding = true;
|
||||
|
||||
/*
|
||||
|
|
@ -3949,49 +3947,9 @@ fctx_nextaddress(fetchctx_t *fctx) {
|
|||
fctx->forwarding = false;
|
||||
FCTX_ATTR_SET(fctx, FCTX_ATTR_TRIEDFIND);
|
||||
|
||||
find = fctx->find;
|
||||
if (find == NULL) {
|
||||
find = ISC_LIST_HEAD(fctx->finds);
|
||||
} else {
|
||||
find = ISC_LIST_NEXT(find, publink);
|
||||
if (find == NULL) {
|
||||
find = ISC_LIST_HEAD(fctx->finds);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the first unmarked addrinfo.
|
||||
*/
|
||||
addrinfo = NULL;
|
||||
if (find != NULL) {
|
||||
start = find;
|
||||
do {
|
||||
for (addrinfo = ISC_LIST_HEAD(find->list);
|
||||
addrinfo != NULL;
|
||||
addrinfo = ISC_LIST_NEXT(addrinfo, publink))
|
||||
{
|
||||
if (!UNMARKED(addrinfo)) {
|
||||
continue;
|
||||
}
|
||||
possibly_mark(fctx, addrinfo);
|
||||
if (UNMARKED(addrinfo)) {
|
||||
addrinfo->flags |= FCTX_ADDRINFO_MARK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (addrinfo != NULL) {
|
||||
break;
|
||||
}
|
||||
find = ISC_LIST_NEXT(find, publink);
|
||||
if (find == NULL) {
|
||||
find = ISC_LIST_HEAD(fctx->finds);
|
||||
}
|
||||
} while (find != start);
|
||||
}
|
||||
|
||||
fctx->find = find;
|
||||
if (addrinfo != NULL) {
|
||||
return addrinfo;
|
||||
faddrinfo = nextaddress(fctx);
|
||||
if (faddrinfo != NULL) {
|
||||
return faddrinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -4072,6 +4030,39 @@ fctx_nextaddress(fetchctx_t *fctx) {
|
|||
return addrinfo;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
incr_query_counters(fetchctx_t *fctx) {
|
||||
isc_result_t result;
|
||||
|
||||
result = isc_counter_increment(fctx->qc);
|
||||
#if WANT_QUERYTRACE
|
||||
FCTXTRACE5("query", "max-recursion-queries, querycount=",
|
||||
isc_counter_used(fctx->qc));
|
||||
#endif
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
|
||||
"exceeded max queries resolving '%s' "
|
||||
"(max-recursion-queries, querycount=%u)",
|
||||
fctx->info, isc_counter_used(fctx->qc));
|
||||
} else if (fctx->gqc != NULL) {
|
||||
result = isc_counter_increment(fctx->gqc);
|
||||
#if WANT_QUERYTRACE
|
||||
FCTXTRACE5("query", "max-query-count, querycount=",
|
||||
isc_counter_used(fctx->gqc));
|
||||
#endif
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
|
||||
"exceeded global max queries resolving "
|
||||
"'%s' (max-query-count, querycount=%u)",
|
||||
fctx->info, isc_counter_used(fctx->gqc));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
fctx_try(fetchctx_t *fctx, bool retrying) {
|
||||
isc_result_t result;
|
||||
|
|
@ -4212,36 +4203,11 @@ fctx_try(fetchctx_t *fctx, bool retrying) {
|
|||
return;
|
||||
}
|
||||
|
||||
result = isc_counter_increment(fctx->qc);
|
||||
#if WANT_QUERYTRACE
|
||||
FCTXTRACE5("query", "max-recursion-queries, querycount=",
|
||||
isc_counter_used(fctx->qc));
|
||||
#endif
|
||||
result = incr_query_counters(fctx);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
|
||||
"exceeded max queries resolving '%s' "
|
||||
"(max-recursion-queries, querycount=%u)",
|
||||
fctx->info, isc_counter_used(fctx->qc));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (fctx->gqc != NULL) {
|
||||
result = isc_counter_increment(fctx->gqc);
|
||||
#if WANT_QUERYTRACE
|
||||
FCTXTRACE5("query", "max-query-count, querycount=",
|
||||
isc_counter_used(fctx->gqc));
|
||||
#endif
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
|
||||
"exceeded global max queries resolving "
|
||||
"'%s' (max-query-count, querycount=%u)",
|
||||
fctx->info, isc_counter_used(fctx->gqc));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
result = fctx_query(fctx, addrinfo, fctx->options);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto done;
|
||||
|
|
@ -7015,6 +6981,13 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* deny-answer-address doesn't apply to non-IN classes.
|
||||
*/
|
||||
if (rdataset->rdclass != dns_rdataclass_in) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, search the filter list for a match for each
|
||||
* address record. If a match is found, the address should be
|
||||
|
|
@ -7680,6 +7653,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
|||
return;
|
||||
|
||||
cleanup:
|
||||
resquery_detach(&rctx->query);
|
||||
isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
|
||||
}
|
||||
|
||||
|
|
@ -8029,6 +8003,7 @@ resquery_response_continue(void *arg, isc_result_t result) {
|
|||
rctx_done(rctx, result);
|
||||
|
||||
cleanup:
|
||||
resquery_detach(&rctx->query);
|
||||
isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
|
||||
}
|
||||
|
||||
|
|
@ -8042,7 +8017,7 @@ static void
|
|||
rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result,
|
||||
isc_region_t *region, respctx_t *rctx) {
|
||||
*rctx = (respctx_t){ .result = result,
|
||||
.query = query,
|
||||
.query = resquery_ref(query),
|
||||
.fctx = fctx,
|
||||
.broken_type = badns_response,
|
||||
.retryopts = query->options };
|
||||
|
|
@ -9746,9 +9721,9 @@ rctx_nextserver(respctx_t *rctx, dns_message_t *message,
|
|||
* rctx_resend():
|
||||
*
|
||||
* Resend the query, probably with the options changed. Calls
|
||||
* fctx_query(), passing rctx->retryopts (which is based on
|
||||
* query->options, but may have been updated since the last time
|
||||
* fctx_query() was called).
|
||||
* fctx_query(), unless query counter limits are hit, passing
|
||||
* rctx->retryopts (which is based on query->options, but may have
|
||||
* been updated since the last time fctx_query() was called).
|
||||
*/
|
||||
static void
|
||||
rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) {
|
||||
|
|
@ -9756,8 +9731,15 @@ rctx_resend(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo) {
|
|||
isc_result_t result;
|
||||
|
||||
FCTXTRACE("resend");
|
||||
inc_stats(fctx->res, dns_resstatscounter_retry);
|
||||
|
||||
CHECK(incr_query_counters(fctx));
|
||||
|
||||
result = fctx_query(fctx, addrinfo, rctx->retryopts);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
inc_stats(fctx->res, dns_resstatscounter_retry);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
fctx_done_detach(&rctx->fctx, result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,15 +190,6 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
|
|||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXDCL need to check for key expiry per 4.1.1
|
||||
* XXXDCL need a way to check fully established, perhaps w/key_flags
|
||||
*/
|
||||
result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
gss_ctx = dst_key_getgssctx(tsigkey->key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set
|
||||
*/
|
||||
|
|
@ -206,25 +197,24 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
|
|||
result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab,
|
||||
&intoken, &outtoken, &gss_ctx, principal,
|
||||
tctx->mctx);
|
||||
if (result == DNS_R_INVALIDTKEY) {
|
||||
if (tsigkey != NULL) {
|
||||
dns_tsigkey_detach(&tsigkey);
|
||||
}
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
tkeyout->error = dns_tsigerror_badkey;
|
||||
tkey_log("process_gsstkey(): dns_tsigerror_badkey");
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) {
|
||||
CHECK(result);
|
||||
result = ISC_R_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times.
|
||||
* Multi-round GSS-API negotiation (GSS_S_CONTINUE_NEEDED) is
|
||||
* rejected in dst_gssapi_acceptctx(), so if we reach here the
|
||||
* negotiation is complete and the principal must be set.
|
||||
*/
|
||||
if (dns_name_countlabels(principal) == 0U) {
|
||||
if (tsigkey != NULL) {
|
||||
dns_tsigkey_detach(&tsigkey);
|
||||
}
|
||||
tkeyout->error = dns_tsigerror_badkey;
|
||||
tkey_log("process_gsstkey(): "
|
||||
"completed context with empty principal");
|
||||
result = ISC_R_SUCCESS;
|
||||
goto cleanup;
|
||||
} else if (tsigkey == NULL) {
|
||||
#if HAVE_GSSAPI
|
||||
OM_uint32 gret, minor, lifetime;
|
||||
|
|
@ -285,6 +275,9 @@ process_gsstkey(dns_message_t *msg, dns_name_t *name, dns_rdata_tkey_t *tkeyin,
|
|||
return ISC_R_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
if (dstkey == NULL && gss_ctx != NULL) {
|
||||
dst_gssapi_deletectx(tctx->mctx, &gss_ctx);
|
||||
}
|
||||
if (tsigkey != NULL) {
|
||||
dns_tsigkey_detach(&tsigkey);
|
||||
}
|
||||
|
|
@ -295,7 +288,9 @@ cleanup:
|
|||
isc_buffer_free(&outtoken);
|
||||
}
|
||||
|
||||
tkey_log("process_gsstkey(): %s", isc_result_totext(result));
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
tkey_log("process_gsstkey(): %s", isc_result_totext(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -689,9 +684,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
|
|||
NULL));
|
||||
|
||||
/*
|
||||
* XXXSRA This seems confused. If we got CONTINUE from initctx,
|
||||
* the GSS negotiation hasn't completed yet, so we can't sign
|
||||
* anything yet.
|
||||
* GSS negotiation is complete (CONTINUE returned earlier).
|
||||
* Create the TSIG key from the established context.
|
||||
*/
|
||||
CHECK(dns_tsigkey_createfromkey(tkeyname, DST_ALG_GSSAPI, dstkey, true,
|
||||
false, NULL, rtkey.inception,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <isc/once.h>
|
||||
#include <isc/os.h>
|
||||
#include <isc/overflow.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/strerr.h>
|
||||
#include <isc/string.h>
|
||||
|
|
@ -131,7 +132,6 @@ struct isc_mem {
|
|||
char name[16];
|
||||
atomic_size_t inuse;
|
||||
atomic_bool hi_called;
|
||||
atomic_bool is_overmem;
|
||||
atomic_size_t hi_water;
|
||||
atomic_size_t lo_water;
|
||||
ISC_LIST(isc_mempool_t) pools;
|
||||
|
|
@ -570,7 +570,6 @@ mem_create(isc_mem_t **ctxp, unsigned int debugging, unsigned int flags,
|
|||
atomic_init(&ctx->hi_water, 0);
|
||||
atomic_init(&ctx->lo_water, 0);
|
||||
atomic_init(&ctx->hi_called, false);
|
||||
atomic_init(&ctx->is_overmem, false);
|
||||
|
||||
ISC_LIST_INIT(ctx->pools);
|
||||
|
||||
|
|
@ -1017,48 +1016,30 @@ bool
|
|||
isc_mem_isovermem(isc_mem_t *ctx) {
|
||||
REQUIRE(VALID_CONTEXT(ctx));
|
||||
|
||||
bool is_overmem = atomic_load_relaxed(&ctx->is_overmem);
|
||||
|
||||
if (!is_overmem) {
|
||||
/* We are not overmem, check whether we should be? */
|
||||
size_t hiwater = atomic_load_relaxed(&ctx->hi_water);
|
||||
if (hiwater == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t inuse = atomic_load_relaxed(&ctx->inuse);
|
||||
if (inuse <= hiwater) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) {
|
||||
fprintf(stderr,
|
||||
"overmem mctx %p inuse %zu hi_water %zu\n", ctx,
|
||||
inuse, hiwater);
|
||||
}
|
||||
|
||||
atomic_store_relaxed(&ctx->is_overmem, true);
|
||||
return true;
|
||||
} else {
|
||||
/* We are overmem, check whether we should not be? */
|
||||
size_t lowater = atomic_load_relaxed(&ctx->lo_water);
|
||||
if (lowater == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t inuse = atomic_load_relaxed(&ctx->inuse);
|
||||
if (inuse >= lowater) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) {
|
||||
fprintf(stderr,
|
||||
"overmem mctx %p inuse %zu lo_water %zu\n", ctx,
|
||||
inuse, lowater);
|
||||
}
|
||||
atomic_store_relaxed(&ctx->is_overmem, false);
|
||||
size_t hiwater = atomic_load_relaxed(&ctx->hi_water);
|
||||
if (hiwater == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t inuse = atomic_load_relaxed(&ctx->inuse);
|
||||
if (inuse >= hiwater) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t lowater = atomic_load_relaxed(&ctx->lo_water);
|
||||
if (inuse <= lowater) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Between lo_water and hi_water, return true with a probability
|
||||
* that ramps linearly from 0 at lo_water to 1 at hi_water. This
|
||||
* spreads cache cleaning across many inserts instead of triggering
|
||||
* a thundering herd once the hi_water mark is crossed.
|
||||
*/
|
||||
uint32_t prob = (uint32_t)(((uint64_t)(inuse - lowater) * 256) /
|
||||
(hiwater - lowater));
|
||||
return isc_random8() < prob;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -2753,6 +2753,8 @@ server_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock,
|
|||
} else {
|
||||
cb(handle, result, cbarg);
|
||||
}
|
||||
|
||||
isc_buffer_initnull(&sock->h2->wbuf);
|
||||
isc__nm_uvreq_put(&req);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3041,13 +3041,17 @@ check_mirror_zone_notify(const cfg_obj_t *zoptions, const char *znamestr,
|
|||
*/
|
||||
static bool
|
||||
check_recursion(const cfg_obj_t *config, const cfg_obj_t *voptions,
|
||||
const cfg_obj_t *goptions, isc_log_t *logctx,
|
||||
cfg_aclconfctx_t *actx, isc_mem_t *mctx) {
|
||||
dns_rdataclass_t vclass, const cfg_obj_t *goptions,
|
||||
isc_log_t *logctx, cfg_aclconfctx_t *actx, isc_mem_t *mctx) {
|
||||
dns_acl_t *acl = NULL;
|
||||
const cfg_obj_t *obj;
|
||||
isc_result_t result;
|
||||
bool retval = true;
|
||||
|
||||
if (vclass != dns_rdataclass_in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the "recursion" option first.
|
||||
*/
|
||||
|
|
@ -3905,7 +3909,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
|
|||
* contradicts the purpose of the former.
|
||||
*/
|
||||
if (ztype == CFG_ZONE_MIRROR &&
|
||||
!check_recursion(config, voptions, goptions, logctx, actx, mctx))
|
||||
!check_recursion(config, voptions, zclass, goptions, logctx, actx,
|
||||
mctx))
|
||||
{
|
||||
cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
|
||||
"zone '%s': mirror zones cannot be used if "
|
||||
|
|
@ -5719,6 +5724,17 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
|
|||
|
||||
cfg_aclconfctx_create(mctx, &actx);
|
||||
|
||||
if (vclass != dns_rdataclass_in) {
|
||||
if (check_recursion(config, voptions, dns_rdataclass_in,
|
||||
options, logctx, actx, mctx))
|
||||
{
|
||||
cfg_obj_log(opts, logctx, ISC_LOG_WARNING,
|
||||
"recursion will be disabled for "
|
||||
"non-IN view '%s'",
|
||||
viewname);
|
||||
}
|
||||
}
|
||||
|
||||
if (voptions != NULL) {
|
||||
(void)cfg_map_get(voptions, "zone", &zones);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include <dns/dispatch.h>
|
||||
#include <dns/dnstap.h>
|
||||
#include <dns/edns.h>
|
||||
#include <dns/enumclass.h>
|
||||
#include <dns/message.h>
|
||||
#include <dns/peer.h>
|
||||
#include <dns/rcode.h>
|
||||
|
|
@ -2041,7 +2042,9 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
|||
}
|
||||
}
|
||||
|
||||
if (client->message->rdclass == 0) {
|
||||
char classbuf[DNS_RDATACLASS_FORMATSIZE];
|
||||
switch (client->message->rdclass) {
|
||||
case dns_rdataclass_reserved0:
|
||||
if ((client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0 &&
|
||||
client->message->opcode == dns_opcode_query &&
|
||||
client->message->counts[DNS_SECTION_QUESTION] == 0U)
|
||||
|
|
@ -2060,12 +2063,46 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
|||
return;
|
||||
}
|
||||
|
||||
ns_client_dumpmessage(client,
|
||||
"message class could not be determined");
|
||||
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
|
||||
return;
|
||||
case dns_rdataclass_in:
|
||||
break;
|
||||
case dns_rdataclass_chaos:
|
||||
break;
|
||||
case dns_rdataclass_hs:
|
||||
break;
|
||||
case dns_rdataclass_none:
|
||||
if (client->message->opcode != dns_opcode_update) {
|
||||
ns_client_dumpmessage(client,
|
||||
"message class NONE can be only "
|
||||
"used in DNS updates");
|
||||
ns_client_error(client, DNS_R_FORMERR);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case dns_rdataclass_any:
|
||||
/*
|
||||
* Required for TKEY negotiation.
|
||||
*/
|
||||
if (client->message->tkey == 0) {
|
||||
ns_client_dumpmessage(client,
|
||||
"message class ANY can be only "
|
||||
"used for TKEY negotiation");
|
||||
ns_client_error(client, DNS_R_FORMERR);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dns_rdataclass_format(client->message->rdclass, classbuf,
|
||||
sizeof(classbuf));
|
||||
ns_client_dumpmessage(client, "");
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
||||
"message class could not be determined");
|
||||
ns_client_dumpmessage(client, "message class could not be "
|
||||
"determined");
|
||||
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
|
||||
"invalid message class: %s", classbuf);
|
||||
|
||||
ns_client_error(client, DNS_R_NOTIMP);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2149,9 +2186,6 @@ ns_client_request_continue(void *arg) {
|
|||
"SIG(0) checks quota reached");
|
||||
|
||||
if (can_log_sigchecks_quota()) {
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_INFO,
|
||||
"SIG(0) checks quota reached");
|
||||
ns_client_dumpmessage(
|
||||
client, "SIG(0) checks quota reached");
|
||||
}
|
||||
|
|
@ -2161,12 +2195,11 @@ ns_client_request_continue(void *arg) {
|
|||
dns_rdataclass_format(client->message->rdclass,
|
||||
classname, sizeof(classname));
|
||||
|
||||
ns_client_dumpmessage(client, "");
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
||||
"no matching view in class '%s'",
|
||||
classname);
|
||||
ns_client_dumpmessage(client,
|
||||
"no matching view in class");
|
||||
}
|
||||
|
||||
dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
|
||||
|
|
@ -2413,6 +2446,10 @@ ns_client_request_continue(void *arg) {
|
|||
break;
|
||||
case dns_opcode_update:
|
||||
CTRACE("update");
|
||||
if (client->view->rdclass != dns_rdataclass_in) {
|
||||
ns_client_error(client, DNS_R_NOTIMP);
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_DNSTAP
|
||||
dns_dt_send(client->view, DNS_DTTYPE_UQ, &client->peeraddr,
|
||||
&client->destsockaddr, transport_type, NULL,
|
||||
|
|
@ -2423,6 +2460,10 @@ ns_client_request_continue(void *arg) {
|
|||
break;
|
||||
case dns_opcode_notify:
|
||||
CTRACE("notify");
|
||||
if (client->view->rdclass != dns_rdataclass_in) {
|
||||
ns_client_error(client, DNS_R_NOTIMP);
|
||||
break;
|
||||
}
|
||||
ns_client_settimeout(client, 60);
|
||||
ns_notify_start(client, client->handle);
|
||||
break;
|
||||
|
|
@ -2796,7 +2837,7 @@ ns_client_dumpmessage(ns_client_t *client, const char *reason) {
|
|||
int len = 1024;
|
||||
isc_result_t result;
|
||||
|
||||
if (!isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
|
||||
if (!isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1)) || reason == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -997,7 +997,9 @@ ssu_checkrr(void *data, rr_t *rr) {
|
|||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
target = &ptr.ptr;
|
||||
}
|
||||
if (rr->rdata.type == dns_rdatatype_srv) {
|
||||
if (rr->rdata.rdclass == dns_rdataclass_in &&
|
||||
rr->rdata.type == dns_rdatatype_srv)
|
||||
{
|
||||
result = dns_rdata_tostruct(&rr->rdata, &srv, NULL);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
target = &srv.target;
|
||||
|
|
@ -1352,7 +1354,10 @@ replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if (db_rr->type == dns_rdatatype_wks) {
|
||||
|
||||
if (db_rr->rdclass == dns_rdataclass_in &&
|
||||
db_rr->type == dns_rdatatype_wks)
|
||||
{
|
||||
/*
|
||||
* Compare the address and protocol fields only. These
|
||||
* form the first five bytes of the RR data. Do a
|
||||
|
|
@ -1495,8 +1500,7 @@ cleanup:
|
|||
* 'rdata', and 'ttl', respectively.
|
||||
*/
|
||||
static void
|
||||
get_current_rr(dns_message_t *msg, dns_section_t section,
|
||||
dns_rdataclass_t zoneclass, dns_name_t **name,
|
||||
get_current_rr(dns_message_t *msg, dns_section_t section, dns_name_t **name,
|
||||
dns_rdata_t *rdata, dns_rdatatype_t *covers, dns_ttl_t *ttl,
|
||||
dns_rdataclass_t *update_class) {
|
||||
dns_rdataset_t *rdataset;
|
||||
|
|
@ -1512,7 +1516,7 @@ get_current_rr(dns_message_t *msg, dns_section_t section,
|
|||
dns_rdataset_current(rdataset, rdata);
|
||||
INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
|
||||
*update_class = rdata->rdclass;
|
||||
rdata->rdclass = zoneclass;
|
||||
rdata->rdclass = dns_rdataclass_in;
|
||||
}
|
||||
|
||||
/*%
|
||||
|
|
@ -1612,7 +1616,6 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
|
|||
dns_message_t *request = client->message;
|
||||
isc_mem_t *mctx = client->manager->mctx;
|
||||
dns_aclenv_t *env = client->manager->aclenv;
|
||||
dns_rdataclass_t zoneclass;
|
||||
dns_rdatatype_t covers;
|
||||
dns_name_t *zonename = NULL;
|
||||
unsigned int *maxbytype = NULL;
|
||||
|
|
@ -1624,11 +1627,13 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
|
|||
|
||||
CHECK(dns_zone_getdb(zone, &db));
|
||||
zonename = dns_db_origin(db);
|
||||
zoneclass = dns_db_class(db);
|
||||
dns_zone_getssutable(zone, &ssutable);
|
||||
options = dns_zone_getoptions(zone);
|
||||
dns_db_currentversion(db, &ver);
|
||||
|
||||
/* Updates are only supported for class IN. */
|
||||
INSIST(dns_zone_getclass(zone) == dns_rdataclass_in);
|
||||
|
||||
/*
|
||||
* Update message processing can leak record existence information
|
||||
* so check that we are allowed to query this zone. Additionally,
|
||||
|
|
@ -1678,13 +1683,13 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
|
|||
|
||||
INSIST(ssutable == NULL || update < maxbytypelen);
|
||||
|
||||
get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
|
||||
&rdata, &covers, &ttl, &update_class);
|
||||
get_current_rr(request, DNS_SECTION_UPDATE, &name, &rdata,
|
||||
&covers, &ttl, &update_class);
|
||||
|
||||
if (!dns_name_issubdomain(name, zonename)) {
|
||||
FAILC(DNS_R_NOTZONE, "update RR is outside zone");
|
||||
}
|
||||
if (update_class == zoneclass) {
|
||||
if (update_class == dns_rdataclass_in) {
|
||||
/*
|
||||
* Check for meta-RRs. The RFC2136 pseudocode says
|
||||
* check for ANY|AXFR|MAILA|MAILB, but the text adds
|
||||
|
|
@ -1698,6 +1703,7 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
|
|||
CHECK(DNS_R_REFUSED);
|
||||
}
|
||||
if ((options & DNS_ZONEOPT_CHECKSVCB) != 0 &&
|
||||
rdata.rdclass == dns_rdataclass_in &&
|
||||
rdata.type == dns_rdatatype_svcb)
|
||||
{
|
||||
result = dns_rdata_checksvcb(name, &rdata);
|
||||
|
|
@ -1785,7 +1791,6 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
|
|||
}
|
||||
|
||||
if (update_class == dns_rdataclass_any &&
|
||||
zoneclass == dns_rdataclass_in &&
|
||||
(rdata.type == dns_rdatatype_ptr ||
|
||||
rdata.type == dns_rdatatype_srv))
|
||||
{
|
||||
|
|
@ -2717,7 +2722,6 @@ update_action(void *arg) {
|
|||
isc_mem_t *mctx = client->manager->mctx;
|
||||
dns_rdatatype_t covers;
|
||||
dns_message_t *request = client->message;
|
||||
dns_rdataclass_t zoneclass;
|
||||
dns_name_t *zonename = NULL;
|
||||
dns_fixedname_t tmpnamefixed;
|
||||
dns_name_t *tmpname = NULL;
|
||||
|
|
@ -2734,9 +2738,10 @@ update_action(void *arg) {
|
|||
|
||||
CHECK(dns_zone_getdb(zone, &db));
|
||||
zonename = dns_db_origin(db);
|
||||
zoneclass = dns_db_class(db);
|
||||
options = dns_zone_getoptions(zone);
|
||||
|
||||
INSIST(dns_zone_getclass(zone) == dns_rdataclass_in);
|
||||
|
||||
is_inline = (!dns_zone_israw(zone) && dns_zone_issecure(zone));
|
||||
is_maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
|
||||
is_signing = is_inline || (!is_inline && is_maintain);
|
||||
|
|
@ -2761,8 +2766,8 @@ update_action(void *arg) {
|
|||
dns_rdataclass_t update_class;
|
||||
bool flag;
|
||||
|
||||
get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
|
||||
&name, &rdata, &covers, &ttl, &update_class);
|
||||
get_current_rr(request, DNS_SECTION_PREREQUISITE, &name, &rdata,
|
||||
&covers, &ttl, &update_class);
|
||||
|
||||
if (ttl != 0) {
|
||||
PREREQFAILC(DNS_R_FORMERR,
|
||||
|
|
@ -2825,7 +2830,7 @@ update_action(void *arg) {
|
|||
"prerequisite not satisfied");
|
||||
}
|
||||
}
|
||||
} else if (update_class == zoneclass) {
|
||||
} else if (update_class == dns_rdataclass_in) {
|
||||
/* "temp<rr.name, rr.type> += rr;" */
|
||||
result = temp_append(&temp, name, &rdata);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -2887,10 +2892,10 @@ update_action(void *arg) {
|
|||
|
||||
INSIST(ssutable == NULL || update < maxbytypelen);
|
||||
|
||||
get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
|
||||
&rdata, &covers, &ttl, &update_class);
|
||||
get_current_rr(request, DNS_SECTION_UPDATE, &name, &rdata,
|
||||
&covers, &ttl, &update_class);
|
||||
|
||||
if (update_class == zoneclass) {
|
||||
if (update_class == dns_rdataclass_in) {
|
||||
/*
|
||||
* RFC1123 doesn't allow MF and MD in master files.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -744,6 +744,7 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
|
|||
bool is_poll = false;
|
||||
bool is_dlz = false;
|
||||
bool is_ixfr = false;
|
||||
bool is_quota_applied = false;
|
||||
bool useviewacl = false;
|
||||
uint32_t begin_serial = 0, current_serial;
|
||||
|
||||
|
|
@ -760,16 +761,6 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
|
|||
|
||||
ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
|
||||
ISC_LOG_DEBUG(6), "%s request", mnemonic);
|
||||
/*
|
||||
* Apply quota.
|
||||
*/
|
||||
result = isc_quota_acquire(&client->manager->sctx->xfroutquota);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING,
|
||||
"%s request denied: %s", mnemonic,
|
||||
isc_result_totext(result));
|
||||
goto max_quota;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interpret the question section.
|
||||
|
|
@ -940,6 +931,19 @@ got_soa:
|
|||
FAILC(DNS_R_FORMERR, "attempted AXFR over UDP");
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply quota after ACL is checked, so that unauthorized clients
|
||||
* can not starve the authorized clients.
|
||||
*/
|
||||
result = isc_quota_acquire(&client->manager->sctx->xfroutquota);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING,
|
||||
"%s request denied: %s", mnemonic,
|
||||
isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
is_quota_applied = true;
|
||||
|
||||
/*
|
||||
* Look up the requesting server in the peer table.
|
||||
*/
|
||||
|
|
@ -1078,7 +1082,7 @@ have_stream:
|
|||
CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf));
|
||||
/*
|
||||
* Create the xfrout context object. This transfers the ownership
|
||||
* of "stream", "db", "ver", and "quota" to the xfrout context object.
|
||||
* of "stream", "db" and "ver" to the xfrout context object.
|
||||
*/
|
||||
|
||||
if (is_dlz) {
|
||||
|
|
@ -1193,10 +1197,13 @@ cleanup:
|
|||
}
|
||||
|
||||
if (xfr != NULL) {
|
||||
/* The quota will be released in xfrout_ctx_destroy(). */
|
||||
INSIST(is_quota_applied);
|
||||
xfrout_fail(xfr, result, "setting up zone transfer");
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
isc_quota_release(&client->manager->sctx->xfroutquota);
|
||||
max_quota:
|
||||
if (is_quota_applied) {
|
||||
isc_quota_release(&client->manager->sctx->xfroutquota);
|
||||
}
|
||||
ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT,
|
||||
NS_LOGMODULE_XFER_OUT, ISC_LOG_DEBUG(3),
|
||||
"zone transfer setup failed");
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ ISC_LOOP_TEST_IMPL(overmempurge_bigrdata) {
|
|||
for (i = 0; !isc_mem_isovermem(mctx2) && i < (maxcache / 10); i++) {
|
||||
overmempurge_addrdataset(db, now, i, 50053, 0, false);
|
||||
}
|
||||
assert_true(isc_mem_isovermem(mctx2));
|
||||
|
||||
/*
|
||||
* Then try to add the same number of entries, each has very large data.
|
||||
|
|
@ -188,7 +187,6 @@ ISC_LOOP_TEST_IMPL(overmempurge_longname) {
|
|||
for (i = 0; !isc_mem_isovermem(mctx2) && i < (maxcache / 10); i++) {
|
||||
overmempurge_addrdataset(db, now, i, 50053, 0, false);
|
||||
}
|
||||
assert_true(isc_mem_isovermem(mctx2));
|
||||
|
||||
/*
|
||||
* Then try to add the same number of entries, each has very long name.
|
||||
|
|
|
|||
|
|
@ -291,6 +291,17 @@ ISC_RUN_TEST_IMPL(isc_mem_reallocate) {
|
|||
isc_mem_free(mctx, data);
|
||||
}
|
||||
|
||||
static bool
|
||||
at_least_one_overmem(isc_mem_t *omctx) {
|
||||
for (size_t i = 0; i < UINT16_MAX; i++) {
|
||||
/* The overmem is probability based in this range */
|
||||
if (isc_mem_isovermem(omctx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(isc_mem_overmem) {
|
||||
isc_mem_t *omctx = NULL;
|
||||
isc_mem_create(&omctx);
|
||||
|
|
@ -298,27 +309,27 @@ ISC_RUN_TEST_IMPL(isc_mem_overmem) {
|
|||
|
||||
isc_mem_setwater(omctx, 1024, 512);
|
||||
|
||||
/* inuse < lo_water */
|
||||
/* inuse <= lo_water is always false */
|
||||
void *data1 = isc_mem_allocate(omctx, 256);
|
||||
assert_false(isc_mem_isovermem(omctx));
|
||||
|
||||
/* lo_water < inuse < hi_water */
|
||||
/* lo_water < inuse < hi_water might be true or false */
|
||||
void *data2 = isc_mem_allocate(omctx, 512);
|
||||
assert_false(isc_mem_isovermem(omctx));
|
||||
assert_true(at_least_one_overmem(omctx));
|
||||
|
||||
/* hi_water < inuse */
|
||||
/* hi_water <= inuse is always true */
|
||||
void *data3 = isc_mem_allocate(omctx, 512);
|
||||
assert_true(isc_mem_isovermem(omctx));
|
||||
|
||||
/* lo_water < inuse < hi_water */
|
||||
/* lo_water < inuse < hi_water might be true or false */
|
||||
isc_mem_free(omctx, data2);
|
||||
assert_true(isc_mem_isovermem(omctx));
|
||||
assert_true(at_least_one_overmem(omctx));
|
||||
|
||||
/* inuse < lo_water */
|
||||
/* inuse <= lo_water is always false */
|
||||
isc_mem_free(omctx, data3);
|
||||
assert_false(isc_mem_isovermem(omctx));
|
||||
|
||||
/* inuse == 0 */
|
||||
/* inuse == 0 is always false */
|
||||
isc_mem_free(omctx, data1);
|
||||
assert_false(isc_mem_isovermem(omctx));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue