Compare commits

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

also, dns_view_issecuredomain() now returns false if
view->enablevalidation is false, so the caller no longer
has to check for that.
2025-03-14 18:29:48 -07:00
Evan Hunt 8368ef5ae7 split out cookie checks from resquery_response_continue()
split the code section that handles cookie issues into a
separate function for better readablity.
2025-03-14 18:29:48 -07:00
Evan Hunt d8778caec7 simplify dns_ncache_add()
there's no longer any reason to have both dns_ncache_add() and
dns_ncache_addoptout().
2025-03-14 18:29:48 -07:00
77 changed files with 2718 additions and 3446 deletions
+6 -6
View File
@@ -383,9 +383,6 @@ stages:
SHOTGUN_ROUNDS: 3
- &shotgun_rule_other
if: '$CI_PIPELINE_SOURCE =~ /^(api|pipeline|schedule|trigger|web)$/'
# when using data from a single run, the overall instability of the results
# causes quite high false positive rate, rerun the test to attemp to reduce those
retry: 1
script:
- if [ -z "$BASELINE" ]; then export BASELINE=$BIND_BASELINE_VERSION; fi # this dotenv variable can't be set in the rules section, because rules are evaluated before any jobs run
- PIPELINE_ID=$(curl -s -X POST --fail
@@ -587,7 +584,7 @@ vulture:
<<: *precheck_job
needs: []
script:
- vulture --exclude "*ans.py,conftest.py,isctest" --ignore-names "pytestmark" bin/tests/system/
- vulture --exclude "*/ans*/ans.py,conftest.py,isctest" --ignore-names "pytestmark" bin/tests/system/
ci-variables:
stage: precheck
@@ -1691,6 +1688,9 @@ respdiff-third-party:
# Performance tests
# Run shotgun:udp right away, but delay other shotgun jobs sligthly in order to
# allow re-use of the built container image. Otherwise, the jobs would do the
# same builds in parallel rather than re-use the already built image.
shotgun:udp:
<<: *shotgun_job
variables:
@@ -1701,7 +1701,7 @@ shotgun:tcp:
<<: *shotgun_job
variables:
SHOTGUN_SCENARIO: tcp
SHOTGUN_TRAFFIC_MULTIPLIER: 12
SHOTGUN_TRAFFIC_MULTIPLIER: 13
shotgun:dot:
<<: *shotgun_job
@@ -1722,7 +1722,7 @@ shotgun:doh-get:
variables:
SHOTGUN_SCENARIO: doh-get
SHOTGUN_TRAFFIC_MULTIPLIER: 3
SHOTGUN_EVAL_THRESHOLD_LATENCY_PCTL_MAX: 0.4 # bump from the default due to increased tail-end jitter
SHOTGUN_EVAL_THRESHOLD_LATENCY_PCTL_MAX: 0.3 # bump from the default due to increased tail-end jitter
rules: *shotgun_rules_manual_mr
.stress-test: &stress_test
+1 -7
View File
@@ -129,7 +129,6 @@ static int maxudp = 0;
/*
* -T options:
*/
static bool cookiealwaysvalid = false;
static bool dropedns = false;
static bool ednsformerr = false;
static bool ednsnotimp = false;
@@ -653,9 +652,7 @@ parse_T_opt(char *option) {
* force the server to behave (or misbehave) in
* specified ways for testing purposes.
*/
if (!strcmp(option, "cookiealwaysvalid")) {
cookiealwaysvalid = true;
} else if (!strcmp(option, "dropedns")) {
if (!strcmp(option, "dropedns")) {
dropedns = true;
} else if (!strcmp(option, "ednsformerr")) {
ednsformerr = true;
@@ -1223,9 +1220,6 @@ setup(void) {
/*
* Modify server context according to command line options
*/
if (cookiealwaysvalid) {
ns_server_setoption(sctx, NS_SERVER_COOKIEALWAYSVALID, true);
}
if (disable4) {
ns_server_setoption(sctx, NS_SERVER_DISABLE4, true);
}
+2 -2
View File
@@ -1603,7 +1603,7 @@ xfrin_xmlrender(dns_zone_t *zone, void *arg) {
isc_sockaddr_format(addrp, addr_buf, sizeof(addr_buf));
TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
} else if (is_presoa) {
dns_zone_getsourceaddr(zone, &addr);
addr = dns_zone_getsourceaddr(zone);
isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR addr_buf));
} else {
@@ -2660,7 +2660,7 @@ xfrin_jsonrender(dns_zone_t *zone, void *arg) {
json_object_object_add(xfrinobj, "localaddr",
json_object_new_string(addr_buf));
} else if (is_presoa) {
dns_zone_getsourceaddr(zone, &addr);
addr = dns_zone_getsourceaddr(zone);
isc_sockaddr_format(&addr, addr_buf, sizeof(addr_buf));
json_object_object_add(xfrinobj, "localaddr",
json_object_new_string(addr_buf));
+8 -6
View File
@@ -1279,22 +1279,22 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
obj = NULL;
result = named_config_get(maps, "parental-source", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setparentalsrc4(zone, cfg_obj_assockaddr(obj));
CHECK(dns_zone_setparentalsrc4(zone, cfg_obj_assockaddr(obj)));
obj = NULL;
result = named_config_get(maps, "parental-source-v6", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setparentalsrc6(zone, cfg_obj_assockaddr(obj));
CHECK(dns_zone_setparentalsrc6(zone, cfg_obj_assockaddr(obj)));
obj = NULL;
result = named_config_get(maps, "notify-source", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj));
CHECK(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
obj = NULL;
result = named_config_get(maps, "notify-source-v6", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj));
CHECK(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
obj = NULL;
result = named_config_get(maps, "notify-to-soa", &obj);
@@ -1938,12 +1938,14 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
obj = NULL;
result = named_config_get(maps, "transfer-source", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setxfrsource4(mayberaw, cfg_obj_assockaddr(obj));
CHECK(dns_zone_setxfrsource4(mayberaw,
cfg_obj_assockaddr(obj)));
obj = NULL;
result = named_config_get(maps, "transfer-source-v6", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setxfrsource6(mayberaw, cfg_obj_assockaddr(obj));
CHECK(dns_zone_setxfrsource6(mayberaw,
cfg_obj_assockaddr(obj)));
obj = NULL;
(void)named_config_get(maps, "try-tcp-refresh", &obj);
+2 -4
View File
@@ -131,13 +131,11 @@ status=$((status + ret))
echo_i "checking that log-report-channel zones fail if '*._er/TXT' is missing ($n)"
ret=0
$CHECKZONE -R fail example zones/er.db >test.out2.$n 2>&1 || ret=1
grep -F "no '*._er/TXT' wildcard found" test.out2.$n >/dev/null && ret=1
grep -F "no '*._er/TXT' wildcard found" test.out4.$n >/dev/null && ret=1
$CHECKZONE example zones/er-missing.db >test.out3.$n 2>&1 || ret=1
grep -F "no '*._er/TXT' wildcard found" test.out3.$n >/dev/null && ret=1
grep -F "no '*._er/TXT' wildcard found" test.out4.$n >/dev/null && ret=1
$CHECKZONE -R fail example zones/er-missing.db >test.out4.$n 2>&1 && ret=1
grep -F "no '*._er/TXT' wildcard found" test.out4.$n >/dev/null || ret=1
n=$((n + 1))
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "checking that raw zone with bad class is handled ($n)"
-1
View File
@@ -308,7 +308,6 @@ def logger(request, system_test_name):
@pytest.fixture(scope="module")
def expected_artifacts(request):
common_artifacts = [
"*/.hypothesis", # drop after Ubuntu 20.04 Focal Fossa gets removed from CI
".libs/*", # possible build artifacts, see GL #5055
"ns*/named.conf",
"ns*/named.memstats",
-17
View File
@@ -361,23 +361,6 @@ grep "status: NOERROR," dig.out.test$n >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "Restart NS4 with -T cookiealwaysvalid ($n)"
stop_server ns4
touch ns4/named.cookiealwaysvalid
start_server --noclean --restart --port ${PORT} ns4 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "test NS6 cookie on NS4 with -T cookiealwaysvalid (expect success) ($n)"
ret=0
$DIG $DIGOPTS +cookie=$ns6cookie -b 10.53.0.4 +nobadcookie soa . @10.53.0.4 >dig.out.test$n || ret=1
grep "; COOKIE:.*(good)" dig.out.test$n >/dev/null || ret=1
grep "status: NOERROR," dig.out.test$n >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "check that test server is correctly configured ($n)"
ret=0
@@ -19,7 +19,6 @@ pytestmark = pytest.mark.extra_artifacts(
"ans*/ans.run",
"ans*/query.log",
"ns1/named_dump.db*",
"ns4/named.cookiealwaysvalid",
]
)
+1 -1
View File
@@ -2191,7 +2191,7 @@ echo_i "checking RRSIG query from cache ($n)"
ret=0
dig_with_opts normalthenrrsig.secure.example. @10.53.0.4 a >/dev/null || ret=1
ans=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.4 rrsig) || ret=1
expect=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.3 rrsig | grep -E '^(A|NSEC)') || ret=1
expect=$(dig_with_opts +short normalthenrrsig.secure.example. @10.53.0.3 rrsig | grep '^\(A\|NSEC\)') || ret=1
test "$ans" = "$expect" || ret=1
# also check that RA is set
dig_with_opts normalthenrrsig.secure.example. @10.53.0.4 rrsig >dig.out.ns4.test$n || ret=1
+35 -103
View File
@@ -224,20 +224,6 @@ class DnsProtocol(enum.Enum):
TCP = enum.auto()
@dataclass(frozen=True)
class Peer:
"""
Pretty-printed connection endpoint.
"""
host: str
port: int
def __str__(self) -> str:
host = f"[{self.host}]" if ":" in self.host else self.host
return f"{host}:{self.port}"
@dataclass
class QueryContext:
"""
@@ -246,7 +232,7 @@ class QueryContext:
query: dns.message.Message
response: dns.message.Message
peer: Peer
peer: Tuple[str, int]
protocol: DnsProtocol
zone: Optional[dns.zone.Zone] = None
soa: Optional[dns.rrset.RRset] = None
@@ -527,110 +513,56 @@ class AsyncDnsServer(AsyncServer):
self._zone_tree.add(zone)
async def _handle_udp(
self, wire: bytes, addr: Tuple[str, int], transport: asyncio.DatagramTransport
self, wire: bytes, peer: Tuple[str, int], transport: asyncio.DatagramTransport
) -> None:
logging.debug("Received UDP message: %s", wire.hex())
peer = Peer(addr[0], addr[1])
responses = self._handle_query(wire, peer, DnsProtocol.UDP)
async for response in responses:
transport.sendto(response, addr)
transport.sendto(response, peer)
async def _handle_tcp(
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
) -> None:
peer_info = writer.get_extra_info("peername")
peer = Peer(peer_info[0], peer_info[1])
logging.debug("Accepted TCP connection from %s", peer)
while True:
try:
wire = await self._read_tcp_query(reader, peer)
if not wire:
break
await self._send_tcp_response(writer, peer, wire)
except ConnectionResetError:
logging.error("TCP connection from %s reset by peer", peer)
return
logging.debug("Closing TCP connection from %s", peer)
writer.close()
await writer.wait_closed()
async def _read_tcp_query(
self, reader: asyncio.StreamReader, peer: Peer
) -> Optional[bytes]:
wire_length = await self._read_tcp_query_wire_length(reader, peer)
if not wire_length:
return None
return await self._read_tcp_query_wire(reader, peer, wire_length)
async def _read_tcp_query_wire_length(
self, reader: asyncio.StreamReader, peer: Peer
) -> Optional[int]:
logging.debug("Receiving TCP message length from %s...", peer)
wire_length_bytes = await self._read_tcp_octets(reader, peer, 2)
if not wire_length_bytes:
return None
wire_length_bytes = await reader.read(2)
(wire_length,) = struct.unpack("!H", wire_length_bytes)
logging.debug("Receiving TCP message (%d octets)...", wire_length)
return wire_length
wire = await reader.read(wire_length)
full_message = wire_length_bytes + wire
logging.debug("Received complete TCP message: %s", full_message.hex())
async def _read_tcp_query_wire(
self, reader: asyncio.StreamReader, peer: Peer, wire_length: int
) -> Optional[bytes]:
logging.debug("Receiving TCP message (%d octets) from %s...", wire_length, peer)
wire = await self._read_tcp_octets(reader, peer, wire_length)
if not wire:
return None
logging.debug("Received complete TCP message from %s: %s", peer, wire.hex())
return wire
async def _read_tcp_octets(
self, reader: asyncio.StreamReader, peer: Peer, expected: int
) -> Optional[bytes]:
buffer = b""
while len(buffer) < expected:
chunk = await reader.read(expected - len(buffer))
if not chunk:
if buffer:
logging.debug(
"Received short TCP message (%d octets) from %s: %s",
len(buffer),
peer,
buffer.hex(),
)
else:
logging.debug("Received disconnect from %s", peer)
return None
logging.debug("Received %d TCP octets from %s", len(chunk), peer)
buffer += chunk
return buffer
async def _send_tcp_response(
self, writer: asyncio.StreamWriter, peer: Peer, wire: bytes
) -> None:
peer = writer.get_extra_info("peername")
responses = self._handle_query(wire, peer, DnsProtocol.TCP)
async for response in responses:
writer.write(response)
await writer.drain()
try:
await writer.drain()
except ConnectionResetError:
logging.error(
"TCP connection from %s reset by peer", self._format_peer(peer)
)
return
def _log_query(self, qctx: QueryContext, peer: Peer, protocol: DnsProtocol) -> None:
writer.close()
await writer.wait_closed()
def _format_peer(self, peer: Tuple[str, int]) -> str:
host = peer[0]
port = peer[1]
if "::" in host:
host = f"[{host}]"
return f"{host}:{port}"
def _log_query(
self, qctx: QueryContext, peer: Tuple[str, int], protocol: DnsProtocol
) -> None:
logging.info(
"Received %s/%s/%s (ID=%d) query from %s (%s)",
qctx.qname.to_text(omit_final_dot=True),
dns.rdataclass.to_text(qctx.qclass),
dns.rdatatype.to_text(qctx.qtype),
qctx.query.id,
peer,
self._format_peer(peer),
protocol.name,
)
logging.debug(
@@ -641,14 +573,14 @@ class AsyncDnsServer(AsyncServer):
self,
qctx: QueryContext,
response: Optional[Union[dns.message.Message, bytes]],
peer: Peer,
peer: Tuple[str, int],
protocol: DnsProtocol,
) -> None:
if not response:
logging.info(
"Not sending a response to query (ID=%d) from %s (%s)",
qctx.query.id,
peer,
self._format_peer(peer),
protocol.name,
)
return
@@ -674,7 +606,7 @@ class AsyncDnsServer(AsyncServer):
len(response.authority),
len(response.additional),
qctx.query.id,
peer,
self._format_peer(peer),
protocol.name,
)
logging.debug(
@@ -686,13 +618,13 @@ class AsyncDnsServer(AsyncServer):
"Sending response (%d bytes) to a query (ID=%d) from %s (%s)",
len(response),
qctx.query.id,
peer,
self._format_peer(peer),
protocol.name,
)
logging.debug("[OUT] %s", response.hex())
async def _handle_query(
self, wire: bytes, peer: Peer, protocol: DnsProtocol
self, wire: bytes, peer: Tuple[str, int], protocol: DnsProtocol
) -> AsyncGenerator[bytes, None]:
"""
Yield wire data to send as a response over the established transport.
+7 -6
View File
@@ -130,7 +130,7 @@ $KEYGEN -G -k rsasha256 -l policies/kasp.conf $zone >keygen.out.$zone.2 2>&1
zone="multisigner-model2.kasp"
echo_i "setting up zone: $zone"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -M 32768:65535 $zone 2>keygen.out.$zone.2)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zone -M 32768:65535 2>keygen.out.$zone.2)
cat "${KSK}.key" | grep -v ";.*" >>"${zone}.db"
cat "${ZSK}.key" | grep -v ";.*" >>"${zone}.db"
# Import the ZSK sets of the other providers into their DNSKEY RRset.
@@ -350,9 +350,10 @@ setup step2.enable-dnssec.autosign
TpubN="now-900s"
# RRSIG TTL: 12 hour (43200 seconds)
# zone-propagation-delay: 5 minutes (300 seconds)
# retire-safety: 20 minutes (1200 seconds)
# Already passed time: -900 seconds
# Total: 42600 seconds
TsbmN="now+42600s"
# Total: 43800 seconds
TsbmN="now+43800s"
keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
CSK=$($KEYGEN -k enable-dnssec -l policies/autosign.conf $keytimes $zone 2>keygen.out.$zone.1)
$SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1
@@ -364,10 +365,10 @@ $SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $i
# Step 3:
# The zone signatures have been published long enough to become OMNIPRESENT.
setup step3.enable-dnssec.autosign
# Passed time since publications: 42600 + 900 = 43500 seconds.
TpubN="now-43500s"
# Passed time since publications: 43800 + 900 = 44700 seconds.
TpubN="now-44700s"
# The key is secure for using in chain of trust when the DNSKEY is OMNIPRESENT.
TcotN="now-42600s"
TcotN="now-43800s"
# We can submit the DS now.
TsbmN="now"
keytimes="-P ${TpubN} -P sync ${TsbmN} -A ${TpubN}"
+41 -41
View File
@@ -127,9 +127,9 @@ setup step2.algorithm-roll.kasp
# The time passed since the new algorithm keys have been introduced is 3 hours.
TactN="now-3h"
TpubN1="now-3h"
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp =
# now - 3h + 6h + 1h = now + 4h
TsbmN1="now+4h"
# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp + publish-safety =
# now - 3h + 6h + 1h + 1h = now + 5h
TsbmN1="now+5h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I now"
zsk1times="-P ${TactN} -A ${TactN} -I now"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
@@ -156,11 +156,11 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
# Step 3:
# The zone signatures are also OMNIPRESENT.
setup step3.algorithm-roll.kasp
# The time passed since the new algorithm keys have been introduced is 7 hours.
TactN="now-7h"
TretN="now-3h"
TpubN1="now-7h"
TsbmN1="now"
# The time passed since the new algorithm keys have been introduced is 9 hours.
TactN="now-9h"
TretN="now-6h"
TpubN1="now-9h"
TsbmN1="now-1h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
@@ -188,11 +188,11 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
# The DS is swapped and can become OMNIPRESENT.
setup step4.algorithm-roll.kasp
# The time passed since the DS has been swapped is 29 hours.
TactN="now-36h"
TretN="now-33h"
TpubN1="now-36h"
TsbmN1="now-29h"
TactN1="now-27h"
TactN="now-38h"
TretN="now-35h"
TpubN1="now-38h"
TsbmN1="now-30h"
TactN1="now-29h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
@@ -220,12 +220,12 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
# The DNSKEY is removed long enough to be HIDDEN.
setup step5.algorithm-roll.kasp
# The time passed since the DNSKEY has been removed is 2 hours.
TactN="now-38h"
TretN="now-35h"
TactN="now-40h"
TretN="now-37h"
TremN="now-2h"
TpubN1="now-38h"
TsbmN1="now-31h"
TactN1="now-29h"
TpubN1="now-40h"
TsbmN1="now-32h"
TactN1="now-31h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
@@ -253,13 +253,13 @@ $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infil
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.algorithm-roll.kasp
# Additional time passed: 7h.
TactN="now-45h"
TretN="now-42h"
TactN="now-47h"
TretN="now-44h"
TremN="now-7h"
TpubN1="now-45h"
TsbmN1="now-38h"
TactN1="now-36h"
TdeaN="now-7h"
TpubN1="now-47h"
TsbmN1="now-39h"
TactN1="now-38h"
TdeaN="now-9h"
ksk1times="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
zsk1times="-P ${TactN} -A ${TactN} -I ${TretN}"
ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}"
@@ -324,11 +324,11 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
# Step 3:
# The zone signatures are also OMNIPRESENT.
setup step3.csk-algorithm-roll.kasp
# The time passed since the new algorithm keys have been introduced is 7 hours.
TactN="now-7h"
TretN="now-3h"
TpubN1="now-7h"
TactN1="now-3h"
# The time passed since the new algorithm keys have been introduced is 9 hours.
TactN="now-9h"
TretN="now-6h"
TpubN1="now-9h"
TactN1="now-6h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
newtimes="-P ${TpubN1} -A ${TpubN1}"
CSK1=$($KEYGEN -k csk-algoroll -l policies/csk1.conf $csktimes $zone 2>keygen.out.$zone.1)
@@ -347,10 +347,10 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
# The DS is swapped and can become OMNIPRESENT.
setup step4.csk-algorithm-roll.kasp
# The time passed since the DS has been swapped is 29 hours.
TactN="now-36h"
TretN="now-33h"
TpubN1="now-36h"
TactN1="now-33h"
TactN="now-38h"
TretN="now-35h"
TpubN1="now-38h"
TactN1="now-35h"
TsubN1="now-29h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
newtimes="-P ${TpubN1} -A ${TpubN1}"
@@ -370,11 +370,11 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
# The DNSKEY is removed long enough to be HIDDEN.
setup step5.csk-algorithm-roll.kasp
# The time passed since the DNSKEY has been removed is 2 hours.
TactN="now-38h"
TretN="now-35h"
TactN="now-40h"
TretN="now-37h"
TremN="now-2h"
TpubN1="now-38h"
TactN1="now-35h"
TpubN1="now-40h"
TactN1="now-37h"
TsubN1="now-31h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
newtimes="-P ${TpubN1} -A ${TpubN1}"
@@ -394,12 +394,12 @@ $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $in
# The RRSIGs have been removed long enough to be HIDDEN.
setup step6.csk-algorithm-roll.kasp
# Additional time passed: 7h.
TactN="now-45h"
TretN="now-42h"
TactN="now-47h"
TretN="now-44h"
TdeaN="now-9h"
TremN="now-7h"
TpubN1="now-45h"
TactN1="now-42h"
TpubN1="now-47h"
TactN1="now-44h"
TsubN1="now-38h"
csktimes="-P ${TactN} -A ${TactN} -P sync ${TactN} -I ${TretN}"
newtimes="-P ${TpubN1} -A ${TpubN1}"
+125 -120
View File
@@ -275,8 +275,9 @@ set_keytimes_csk_policy() {
set_keytime "KEY1" "ACTIVE" "${created}"
# The DS can be published if the DNSKEY and RRSIG records are
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 86700
# publish-safety (1h) plus zone-propagation-delay (300s) =
# 86400 + 3600 + 300 = 90300.
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 90300
# Key lifetime is unlimited, so not setting RETIRED and REMOVED.
}
@@ -768,8 +769,9 @@ set_keytimes_algorithm_policy() {
# The DS can be published if the DNSKEY and RRSIG records are
# OMNIPRESENT. This happens after max-zone-ttl (1d) plus
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
# publish-safety (1h) plus zone-propagation-delay (300s) =
# 86400 + 3600 + 300 = 90300.
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
# Key lifetime is 10 years, 315360000 seconds.
set_addkeytime "KEY1" "RETIRED" "${published}" 315360000
# The key is removed after the retire time plus DS TTL (1d),
@@ -1718,10 +1720,10 @@ published=$(awk '{print $3}' <published.test${n}.key1)
set_keytime "KEY1" "PUBLISHED" "${published}"
set_keytime "KEY1" "ACTIVE" "${published}"
published=$(key_get KEY1 PUBLISHED)
# The DS can be published if the zone is fully signed.
# This happens after max-zone-ttl (1d) plus
# zone-propagation-delay (300s) = 86400 + 300 = 86700.
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 86700
# The DS can be published if the DNSKEY and RRSIG records are OMNIPRESENT.
# This happens after max-zone-ttl (1d) plus publish-safety (1h) plus
# zone-propagation-delay (300s) = 86400 + 3600 + 300 = 90300.
set_addkeytime "KEY1" "SYNCPUBLISH" "${published}" 90300
# Key lifetime is 6 months, 315360000 seconds.
set_addkeytime "KEY1" "RETIRED" "${published}" 16070400
# The key is removed after the retire time plus DS TTL (1d), parent
@@ -2484,9 +2486,9 @@ set_keytime "KEY1" "PUBLISHED" "${created}"
set_keytime "KEY1" "ACTIVE" "${created}"
# - The DS can be published if the DNSKEY and RRSIG records are
# OMNIPRESENT. This happens after max-zone-ttl (12h) plus
# plus zone-propagation-delay (5m) =
# 43200 + 300 = 43500.
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43500
# publish-safety (5m) plus zone-propagation-delay (5m) =
# 43200 + 300 + 300 = 43800.
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
# - Key lifetime is unlimited, so not setting RETIRED and REMOVED.
# Various signing policy checks.
@@ -2554,7 +2556,7 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "PUBLISHED" "${created}" -900
set_addkeytime "KEY1" "ACTIVE" "${created}" -900
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 42600
set_addkeytime "KEY1" "SYNCPUBLISH" "${created}" 43800
# Continue signing policy checks.
check_keytimes
@@ -2564,8 +2566,8 @@ dnssec_verify
# Next key event is when the zone signatures become OMNIPRESENT: max-zone-ttl
# plus zone propagation delay plus retire safety minus the already elapsed
# 900 seconds: 12h + 300s + 20m - 900 = 43500 - 900 = 42600 seconds
check_next_key_event 42600
# 900 seconds: 12h + 300s + 20m - 900 = 44700 - 900 = 43800 seconds
check_next_key_event 43800
#
# Zone: step3.enable-dnssec.autosign.
@@ -2582,10 +2584,10 @@ check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The key was published and activated 43500 seconds ago (with settime).
# - The key was published and activated 44700 seconds ago (with settime).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "PUBLISHED" "${created}" -43500
set_addkeytime "KEY1" "ACTIVE" "${created}" -43500
set_addkeytime "KEY1" "PUBLISHED" "${created}" -44700
set_addkeytime "KEY1" "ACTIVE" "${created}" -44700
set_keytime "KEY1" "SYNCPUBLISH" "${created}"
# Continue signing policy checks.
@@ -2601,8 +2603,8 @@ check_cdslog "$DIR" "$ZONE" KEY1
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "published" "$ZONE"
# Next key event is when the DS can move to the OMNIPRESENT state. This occurs
# when the parent propagation delay have passed, plus the DS TTL and retire
# safety delay: 1h + 2h = 3h = 10800 seconds
check_next_key_event 10800
# safety delay: 1h + 2h + 20m = 3h20m = 12000 seconds
check_next_key_event 12000
#
# Zone: step4.enable-dnssec.autosign.
@@ -4386,9 +4388,9 @@ check_subdomain
dnssec_verify
# Next key event is when the DS becomes HIDDEN. This happens after the
# parent propagation delay, and DS TTL:
# 1h + 1d = 25h = 90000 seconds.
check_next_key_event 90000
# parent propagation delay, retire safety delay, and DS TTL:
# 1h + 1h + 1d = 26h = 93600 seconds.
check_next_key_event 93600
#
# Zone: step2.going-insecure.kasp
@@ -4454,8 +4456,8 @@ dnssec_verify
# Next key event is when the DS becomes HIDDEN. This happens after the
# parent propagation delay, retire safety delay, and DS TTL:
# 1h + 1d = 25h = 90000 seconds.
check_next_key_event 90000
# 1h + 1h + 1d = 26h = 93600 seconds.
check_next_key_event 93600
#
# Zone: step2.going-insecure-dynamic.kasp
@@ -4649,11 +4651,12 @@ set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
created=$(key_get KEY3 CREATED)
set_keytime "KEY3" "PUBLISHED" "${created}"
set_keytime "KEY3" "ACTIVE" "${created}"
# - It takes TTLsig + Dprp to propagate the zone.
# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
# TTLsig: 6h (39600 seconds)
# Dprp: 1h (3600 seconds)
# Ipub: 7h (25200 seconds)
Ipub=25200
# publish-safety: 1h (3600 seconds)
# Ipub: 8h (28800 seconds)
Ipub=28800
set_addkeytime "KEY3" "SYNCPUBLISH" "${created}" "${Ipub}"
# - The new ZSK is published and activated.
created=$(key_get KEY4 CREATED)
@@ -4722,12 +4725,12 @@ dnssec_verify
# Next key event is when all zone signatures are signed with the new
# algorithm. This is the max-zone-ttl plus zone propagation delay
# 6h + 1h. But three hours have already passed (the time it took to
# make the DNSKEY omnipresent), so the next event should be scheduled
# in 4 hour: 14400 seconds. Prevent intermittent
# plus retire safety: 6h + 1h + 2h. But three hours have already passed
# (the time it took to make the DNSKEY omnipresent), so the next event
# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
# false positives on slow platforms by subtracting the number of seconds
# which passed between key creation and invoking 'rndc reconfig'.
next_time=$((14400 - time_passed))
next_time=$((21600 - time_passed))
check_next_key_event $next_time
#
@@ -4750,28 +4753,28 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
check_cdslog "$DIR" "$ZONE" KEY3
# Set expected key times:
# - The old keys were activated 7 hours ago (25200 seconds).
rollover_predecessor_keytimes -25200
# - And retired 3 hours ago (10800 seconds).
# - The old keys were activated 9 hours ago (32400 seconds).
rollover_predecessor_keytimes -32400
# - And retired 6 hours ago (21600 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -10800
set_addkeytime "KEY1" "RETIRED" "${created}" -21600
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "RETIRED" "${created}" -10800
set_addkeytime "KEY2" "RETIRED" "${created}" -21600
retired=$(key_get KEY2 RETIRED)
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
# - The new keys are published 7 hours ago.
# - The new keys are published 9 hours ago.
created=$(key_get KEY3 CREATED)
set_addkeytime "KEY3" "PUBLISHED" "${created}" -25200
set_addkeytime "KEY3" "ACTIVE" "${created}" -25200
set_addkeytime "KEY3" "PUBLISHED" "${created}" -32400
set_addkeytime "KEY3" "ACTIVE" "${created}" -32400
published=$(key_get KEY3 PUBLISHED)
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
created=$(key_get KEY4 CREATED)
set_addkeytime "KEY4" "PUBLISHED" "${created}" -25200
set_addkeytime "KEY4" "ACTIVE" "${created}" -25200
set_addkeytime "KEY4" "PUBLISHED" "${created}" -32400
set_addkeytime "KEY4" "ACTIVE" "${created}" -32400
# Continue signing policy checks.
check_keytimes
@@ -4784,9 +4787,9 @@ dnssec_verify
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
rndc_checkds "$SERVER" "$DIR" KEY3 "now" "published" "$ZONE"
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
# parent propagation delay, and DS TTL:
# 1h + 2h = 3h = 10800 seconds.
check_next_key_event 10800
# parent propagation delay, retire safety delay, and DS TTL:
# 1h + 2h + 2h = 5h = 18000 seconds.
check_next_key_event 18000
#
# Zone: step4.algorithm-roll.kasp
@@ -4813,29 +4816,29 @@ wait_for_done_signing
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The old keys were activated 36 hours ago (129600 seconds).
rollover_predecessor_keytimes -129600
# - And retired 33 hours ago (118800 seconds).
# - The old keys were activated 38 hours ago (136800 seconds).
rollover_predecessor_keytimes -136800
# - And retired 35 hours ago (126000 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -118800
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "RETIRED" "${created}" -118800
set_addkeytime "KEY2" "RETIRED" "${created}" -126000
retired=$(key_get KEY2 RETIRED)
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
# - The new keys are published 36 hours ago.
# - The new keys are published 38 hours ago.
created=$(key_get KEY3 CREATED)
set_addkeytime "KEY3" "PUBLISHED" "${created}" -129600
set_addkeytime "KEY3" "ACTIVE" "${created}" -129600
set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
published=$(key_get KEY3 PUBLISHED)
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
created=$(key_get KEY4 CREATED)
set_addkeytime "KEY4" "PUBLISHED" "${created}" -129600
set_addkeytime "KEY4" "ACTIVE" "${created}" -129600
set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
# Continue signing policy checks.
check_keytimes
@@ -4864,29 +4867,29 @@ wait_for_done_signing
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The old keys were activated 38 hours ago (136800 seconds)
rollover_predecessor_keytimes -136800
# - And retired 35 hours ago (126000 seconds).
# - The old keys were activated 40 hours ago (144000 seconds)
rollover_predecessor_keytimes -144000
# - And retired 37 hours ago (133200 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
set_addkeytime "KEY1" "RETIRED" "${created}" -133200
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "RETIRED" "${created}" -126000
set_addkeytime "KEY2" "RETIRED" "${created}" -133200
retired=$(key_get KEY2 RETIRED)
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
# The new keys are published 40 hours ago.
created=$(key_get KEY3 CREATED)
set_addkeytime "KEY3" "PUBLISHED" "${created}" -136800
set_addkeytime "KEY3" "ACTIVE" "${created}" -136800
set_addkeytime "KEY3" "PUBLISHED" "${created}" -144000
set_addkeytime "KEY3" "ACTIVE" "${created}" -144000
published=$(key_get KEY3 PUBLISHED)
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
created=$(key_get KEY4 CREATED)
set_addkeytime "KEY4" "PUBLISHED" "${created}" -136800
set_addkeytime "KEY4" "ACTIVE" "${created}" -136800
set_addkeytime "KEY4" "PUBLISHED" "${created}" -144000
set_addkeytime "KEY4" "ACTIVE" "${created}" -144000
# Continue signing policy checks.
check_keytimes
@@ -4895,12 +4898,12 @@ check_subdomain
dnssec_verify
# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
# after the max-zone-ttl plus zone propagation delay (6h + 1h)
# minus the time already passed since the UNRETENTIVE state has
# been reached (2h): 7h - 2h = 5h = 18000 seconds. Prevent intermittent
# after the max-zone-ttl plus zone propagation delay plus retire safety
# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
# false positives on slow platforms by subtracting the number of seconds
# which passed between key creation and invoking 'rndc reconfig'.
next_time=$((18000 - time_passed))
next_time=$((25200 - time_passed))
check_next_key_event $next_time
#
@@ -4918,29 +4921,29 @@ wait_for_done_signing
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The old keys were activated 45 hours ago (162000 seconds)
rollover_predecessor_keytimes -162000
# - And retired 42 hours ago (151200 seconds).
# - The old keys were activated 47 hours ago (169200 seconds)
rollover_predecessor_keytimes -169200
# - And retired 44 hours ago (158400 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -151200
set_addkeytime "KEY1" "RETIRED" "${created}" -158400
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretKSK}"
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "RETIRED" "${created}" -151200
set_addkeytime "KEY2" "RETIRED" "${created}" -158400
retired=$(key_get KEY2 RETIRED)
set_addkeytime "KEY2" "REMOVED" "${retired}" "${IretZSK}"
# The new keys are published 47 hours ago.
created=$(key_get KEY3 CREATED)
set_addkeytime "KEY3" "PUBLISHED" "${created}" -162000
set_addkeytime "KEY3" "ACTIVE" "${created}" -162000
set_addkeytime "KEY3" "PUBLISHED" "${created}" -169200
set_addkeytime "KEY3" "ACTIVE" "${created}" -169200
published=$(key_get KEY3 PUBLISHED)
set_addkeytime "KEY3" "SYNCPUBLISH" "${published}" ${Ipub}
created=$(key_get KEY4 CREATED)
set_addkeytime "KEY4" "PUBLISHED" "${created}" -162000
set_addkeytime "KEY4" "ACTIVE" "${created}" -162000
set_addkeytime "KEY4" "PUBLISHED" "${created}" -169200
set_addkeytime "KEY4" "ACTIVE" "${created}" -169200
# Continue signing policy checks.
check_keytimes
@@ -5023,8 +5026,9 @@ set_keytime "KEY2" "ACTIVE" "${created}"
# - It takes TTLsig + Dprp + publish-safety hours to propagate the zone.
# TTLsig: 6h (39600 seconds)
# Dprp: 1h (3600 seconds)
# Ipub: 7h (25200 seconds)
Ipub=25200
# publish-safety: 1h (3600 seconds)
# Ipub: 8h (28800 seconds)
Ipub=28800
set_addkeytime "KEY2" "SYNCPUBLISH" "${created}" "${Ipub}"
# Continue signing policy checks.
@@ -5078,13 +5082,14 @@ check_apex
check_subdomain
dnssec_verify
# Next key event is when all zone signatures are signed with the new algorithm.
# This is the max-zone-ttl plus zone propagation delay: 6h + 1h. But three
# hours have already passed (the time it took to make the DNSKEY omnipresent),
# so the next event should be scheduled in 4 hour: 14400 seconds. Prevent
# intermittent false positives on slow platforms by subtracting the number of
# seconds which passed between key creation and invoking 'rndc reconfig'.
next_time=$((14400 - time_passed))
# Next key event is when all zone signatures are signed with the new
# algorithm. This is the max-zone-ttl plus zone propagation delay
# plus retire safety: 6h + 1h + 2h. But three hours have already passed
# (the time it took to make the DNSKEY omnipresent), so the next event
# should be scheduled in 6 hour: 21600 seconds. Prevent intermittent
# false positives on slow platforms by subtracting the number of seconds
# which passed between key creation and invoking 'rndc reconfig'.
next_time=$((21600 - time_passed))
check_next_key_event $next_time
#
@@ -5109,17 +5114,17 @@ check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
check_cdslog "$DIR" "$ZONE" KEY2
# Set expected key times:
# - The old key was activated 7 hours ago (25200 seconds).
csk_rollover_predecessor_keytimes -25200
# - And was retired 3 hours ago (10800 seconds).
# - The old key was activated 9 hours ago (32400 seconds).
csk_rollover_predecessor_keytimes -32400
# - And was retired 6 hours ago (21600 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -10800
set_addkeytime "KEY1" "RETIRED" "${created}" -21600
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
# - The new key was published 9 hours ago.
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "PUBLISHED" "${created}" -25200
set_addkeytime "KEY2" "ACTIVE" "${created}" -25200
set_addkeytime "KEY2" "PUBLISHED" "${created}" -32400
set_addkeytime "KEY2" "ACTIVE" "${created}" -32400
published=$(key_get KEY2 PUBLISHED)
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" "${Ipub}"
@@ -5133,9 +5138,9 @@ dnssec_verify
rndc_checkds "$SERVER" "$DIR" KEY1 "now" "withdrawn" "$ZONE"
rndc_checkds "$SERVER" "$DIR" KEY2 "now" "published" "$ZONE"
# Next key event is when the DS becomes OMNIPRESENT. This happens after the
# parent propagation delay, and DS TTL:
# 1h + 2h = 3h = 10800 seconds.
check_next_key_event 10800
# parent propagation delay, retire safety delay, and DS TTL:
# 1h + 2h + 2h = 5h = 18000 seconds.
check_next_key_event 18000
#
# Zone: step4.csk-algorithm-roll.kasp
@@ -5159,17 +5164,17 @@ wait_for_done_signing
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The old keys were activated 36 hours ago (129600 seconds).
csk_rollover_predecessor_keytimes -129600
# - And retired 33 hours ago (118800 seconds).
# - The old key was activated 38 hours ago (136800 seconds)
csk_rollover_predecessor_keytimes -136800
# - And retired 35 hours ago (126000 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -118800
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
# - The new key was published 36 hours ago.
# - The new key was published 38 hours ago.
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "PUBLISHED" "${created}" -129600
set_addkeytime "KEY2" "ACTIVE" "${created}" -129600
set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
published=$(key_get KEY2 PUBLISHED)
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
@@ -5199,17 +5204,17 @@ wait_for_done_signing
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The old key was activated 38 hours ago (136800 seconds)
csk_rollover_predecessor_keytimes -136800
# - And retired 35 hours ago (126000 seconds).
# - The old key was activated 40 hours ago (144000 seconds)
csk_rollover_predecessor_keytimes -144000
# - And retired 37 hours ago (133200 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -126000
set_addkeytime "KEY1" "RETIRED" "${created}" -133200
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
# - The new key was published 38 hours ago.
# - The new key was published 40 hours ago.
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "PUBLISHED" "${created}" -136800
set_addkeytime "KEY2" "ACTIVE" "${created}" -136800
set_addkeytime "KEY2" "PUBLISHED" "${created}" -144000
set_addkeytime "KEY2" "ACTIVE" "${created}" -144000
published=$(key_get KEY2 PUBLISHED)
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
@@ -5220,12 +5225,12 @@ check_subdomain
dnssec_verify
# Next key event is when the RSASHA1 signatures become HIDDEN. This happens
# after the max-zone-ttl plus zone propagation delay (6h + 1h) minus the
# time already passed since the UNRETENTIVE state has been reached (2h):
# 7h - 2h = 5h = 18000 seconds. Prevent intermittent false positives on slow
# platforms by subtracting the number of seconds which passed between key
# creation and invoking 'rndc reconfig'.
next_time=$((18000 - time_passed))
# after the max-zone-ttl plus zone propagation delay plus retire safety
# (6h + 1h + 2h) minus the time already passed since the UNRETENTIVE state has
# been reached (2h): 9h - 2h = 7h = 25200 seconds. Prevent intermittent
# false positives on slow platforms by subtracting the number of seconds
# which passed between key creation and invoking 'rndc reconfig'.
next_time=$((25200 - time_passed))
check_next_key_event $next_time
#
@@ -5243,17 +5248,17 @@ wait_for_done_signing
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
# Set expected key times:
# - The old keys were activated 45 hours ago (162000 seconds)
csk_rollover_predecessor_keytimes -162000
# - And retired 42 hours ago (151200 seconds).
# - The old keys were activated 47 hours ago (169200 seconds)
csk_rollover_predecessor_keytimes -169200
# - And retired 44 hours ago (158400 seconds).
created=$(key_get KEY1 CREATED)
set_addkeytime "KEY1" "RETIRED" "${created}" -151200
set_addkeytime "KEY1" "RETIRED" "${created}" -158400
retired=$(key_get KEY1 RETIRED)
set_addkeytime "KEY1" "REMOVED" "${retired}" "${IretCSK}"
# - The new key was published 47 hours ago.
created=$(key_get KEY2 CREATED)
set_addkeytime "KEY2" "PUBLISHED" "${created}" -162000
set_addkeytime "KEY2" "ACTIVE" "${created}" -162000
set_addkeytime "KEY2" "PUBLISHED" "${created}" -169200
set_addkeytime "KEY2" "ACTIVE" "${created}" -169200
published=$(key_get KEY2 PUBLISHED)
set_addkeytime "KEY2" "SYNCPUBLISH" "${published}" ${Ipub}
@@ -1,17 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 30 SOA ns2.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns2.good.
8.2.6.0 60 NS ns3.good.
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0 1 PTR nee.com.
+436 -91
View File
@@ -1,111 +1,456 @@
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
# 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.
SPDX-License-Identifier: MPL-2.0
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
"""
from typing import AsyncGenerator
import dns.message
import dns.name
import dns.rcode
import dns.rdataclass
import dns.rdatatype
from isctest.asyncserver import (
AsyncDnsServer,
DnsResponseSend,
DomainHandler,
QueryContext,
ResponseAction,
)
from qmin_ans import (
DelayedResponseHandler,
EntRcodeChanger,
QueryLogHandler,
log_query,
)
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
class QueryLogger(QueryLogHandler):
domains = ["1.0.0.2.ip6.arpa.", "fwd.", "good."]
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
class BadHandler(EntRcodeChanger):
domains = ["bad."]
rcode = dns.rcode.NXDOMAIN
def endswith(domain, labels):
return domain.endswith("." + labels) or domain == labels
class UglyHandler(EntRcodeChanger):
domains = ["ugly."]
rcode = dns.rcode.FORMERR
############################################################################
# Respond to a DNS query.
# For good. it serves:
# ns2.good. IN A 10.53.0.2
# zoop.boing.good. NS ns3.good.
# ns3.good. IN A 10.53.0.3
# too.many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.good. A 192.0.2.2
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 milliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage to non-empty terminals
#
# For 1.0.0.2.ip6.arpa it serves
# 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa. IN PTR nee.com.
# 8.2.6.0.1.0.0.2.ip6.arpa IN NS ns3.good
# 1.0.0.2.ip6.arpa. IN NS ns2.good
# ip6.arpa. IN NS ns2.good
#
# For stale. it serves:
# a.b. NS ns.a.b.stale.
# ns.a.b.stale. IN A 10.53.0.3
# b. NS ns.b.stale.
# ns.b.stale. IN A 10.53.0.4
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split(".")
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
ugly = False
slow = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
if endswith(lqname, "1.0.0.2.ip6.arpa."):
# Direct query - give direct answer
if endswith(lqname, "8.2.6.0.1.0.0.2.ip6.arpa."):
# Delegate to ns3
r.authority.append(
dns.rrset.from_text(
"8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, NS, "ns3.good."
)
)
r.additional.append(
dns.rrset.from_text("ns3.good.", 60, IN, A, "10.53.0.3")
)
elif (
lqname
== "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa."
and rrtype == PTR
):
# Direct query - give direct answer
r.answer.append(
dns.rrset.from_text(
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.",
1,
IN,
PTR,
"nee.com.",
)
)
r.flags |= dns.flags.AA
elif lqname == "1.0.0.2.ip6.arpa." and rrtype == NS:
# NS query at the apex
r.answer.append(
dns.rrset.from_text("1.0.0.2.ip6.arpa.", 30, IN, NS, "ns2.good.")
)
r.flags |= dns.flags.AA
elif endswith(
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.",
lqname,
):
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"1.0.0.2.ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"1.0.0.2.ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
r.set_rcode(NXDOMAIN)
return r
elif endswith(lqname, "ip6.arpa."):
if lqname == "ip6.arpa." and rrtype == NS:
# NS query at the apex
r.answer.append(dns.rrset.from_text("ip6.arpa.", 30, IN, NS, "ns2.good."))
r.flags |= dns.flags.AA
elif endswith("1.0.0.2.ip6.arpa.", lqname):
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"ip6.arpa.",
30,
IN,
SOA,
"ns2.good. hostmaster.arpa. 2018050100 1 1 1 1",
)
)
r.set_rcode(NXDOMAIN)
return r
elif endswith(lqname, "stale."):
if endswith(lqname, "a.b.stale."):
# Delegate to ns.a.b.stale.
r.authority.append(
dns.rrset.from_text("a.b.stale.", 2, IN, NS, "ns.a.b.stale.")
)
r.additional.append(
dns.rrset.from_text("ns.a.b.stale.", 2, IN, A, "10.53.0.3")
)
elif endswith(lqname, "b.stale."):
# Delegate to ns.b.stale.
r.authority.append(
dns.rrset.from_text("b.stale.", 2, IN, NS, "ns.b.stale.")
)
r.additional.append(
dns.rrset.from_text("ns.b.stale.", 2, IN, A, "10.53.0.4")
)
elif lqname == "stale." and rrtype == NS:
# NS query at the apex.
r.answer.append(dns.rrset.from_text("stale.", 2, IN, NS, "ns2.stale."))
r.flags |= dns.flags.AA
elif lqname == "stale." and rrtype == SOA:
# SOA query at the apex.
r.answer.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.stale. 1 2 3 4 5"
)
)
r.flags |= dns.flags.AA
elif lqname == "stale.":
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"
)
)
r.flags |= dns.flags.AA
elif lqname == "ns2.stale.":
if rrtype == A:
r.additional.append(
dns.rrset.from_text("ns.b.stale.", 2, IN, A, "10.53.0.2")
)
else:
r.authority.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"
)
)
r.flags |= dns.flags.AA
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"
)
)
r.set_rcode(NXDOMAIN)
return r
elif endswith(lqname, "bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif endswith(lqname, "ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif endswith(lqname, "good."):
suffix = "good."
lqname = lqname[:-5]
elif endswith(lqname, "slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
elif endswith(lqname, "fwd."):
suffix = "fwd."
lqname = lqname[:-4]
else:
r.set_rcode(REFUSED)
return r
# Good/bad/ugly differs only in how we treat non-empty terminals
if endswith(lqname, "zoop.boing."):
r.authority.append(
dns.rrset.from_text("zoop.boing." + suffix, 1, IN, NS, "ns3." + suffix)
)
elif (
lqname == "many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z."
and rrtype == A
):
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.2"))
r.flags |= dns.flags.AA
elif lqname == "" and rrtype == NS:
r.answer.append(dns.rrset.from_text(suffix, 30, IN, NS, "ns2." + suffix))
r.flags |= dns.flags.AA
elif lqname == "ns2.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns2." + suffix, 30, IN, A, "10.53.0.2")
)
elif rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"ns2." + suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::2"
)
)
else:
r.authority.append(
dns.rrset.from_text(
suffix,
30,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
elif lqname == "ns3.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns3." + suffix, 30, IN, A, "10.53.0.3")
)
elif lqname == "ns3." and rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"ns3." + suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::3"
)
)
else:
r.authority.append(
dns.rrset.from_text(
suffix,
30,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
elif lqname == "ns4.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns4." + suffix, 30, IN, A, "10.53.0.4")
)
elif rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"ns4." + suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::4"
)
)
else:
r.authority.append(
dns.rrset.from_text(
suffix,
30,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
elif lqname == "a.bit.longer.ns.name." and rrtype == A:
r.answer.append(
dns.rrset.from_text("a.bit.longer.ns.name." + suffix, 1, IN, A, "10.53.0.4")
)
r.flags |= dns.flags.AA
elif lqname == "a.bit.longer.ns.name." and rrtype == AAAA:
r.answer.append(
dns.rrset.from_text(
"a.bit.longer.ns.name." + suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::4"
)
)
r.flags |= dns.flags.AA
else:
r.authority.append(
dns.rrset.from_text(
suffix,
1,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
if bad or not (
endswith("icky.icky.icky.ptang.zoop.boing.", lqname)
or endswith(
"many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.",
lqname,
)
or endswith("a.bit.longer.ns.name.", lqname)
):
r.set_rcode(NXDOMAIN)
if ugly:
r.set_rcode(FORMERR)
if slow:
time.sleep(0.2)
return r
class SlowHandler(DelayedResponseHandler):
domains = ["slow."]
delay = 0.2
def sigterm(signum, frame):
print("Shutting down now...")
os.remove("ans.pid")
running = False
sys.exit(0)
def send_delegation(
qctx: QueryContext, zone_cut: dns.name.Name, target_addr: str
) -> ResponseAction:
"""
Delegate `zone_cut` to a single in-bailiwick name server, `ns.<zone_cut>`,
with a single IPv4 glue record (provided in `target_addr`) included in the
ADDITIONAL section.
"""
ns_name = "ns." + zone_cut.to_text()
ns_rrset = dns.rrset.from_text(
zone_cut, 2, dns.rdataclass.IN, dns.rdatatype.NS, ns_name
)
a_rrset = dns.rrset.from_text(
ns_name, 2, dns.rdataclass.IN, dns.rdatatype.A, target_addr
)
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.2"
ip6 = "fd92:7065:b8e:ffff::2"
response = dns.message.make_response(qctx.query)
response.set_rcode(dns.rcode.NOERROR)
response.authority.append(ns_rrset)
response.additional.append(a_rrset)
try:
port = int(os.environ["PORT"])
except:
port = 5300
return DnsResponseSend(response, authoritative=False)
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
class StaleHandler(DomainHandler):
"""
`a.b.stale` is a subdomain of `b.stale` and these two subdomains need to be
delegated to different name servers. Therefore, their delegations cannot
be placed in the zone file because the zone cut at `b.stale` would occlude
the one at `a.b.stale`. Generate these delegations dynamically depending
on the QNAME.
"""
signal.signal(signal.SIGTERM, sigterm)
domains = ["stale."]
f = open("ans.pid", "w")
pid = os.getpid()
print(pid, file=f)
f.close()
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
a_b_stale = dns.name.from_text("a.b.stale.")
b_stale = dns.name.from_text("b.stale.")
if qctx.qname.is_subdomain(a_b_stale):
yield send_delegation(qctx, a_b_stale, "10.53.0.3")
elif qctx.qname.is_subdomain(b_stale):
yield send_delegation(qctx, b_stale, "10.53.0.4")
running = True
print("Listening on %s port %d" % (ip4, port))
if havev6:
print("Listening on %s port %d" % (ip6, port))
print("Ctrl-c to quit")
if __name__ == "__main__":
server = AsyncDnsServer()
server.install_response_handler(QueryLogger())
server.install_response_handler(BadHandler())
server.install_response_handler(UglyHandler())
server.install_response_handler(SlowHandler())
server.install_response_handler(StaleHandler())
server.run()
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print(
"Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
)
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break
-1
View File
@@ -1 +0,0 @@
good.db
-1
View File
@@ -1 +0,0 @@
good.db
-26
View File
@@ -1,26 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns2 hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns2
ns2 30 A 10.53.0.2
30 AAAA fd92:7065:b8e:ffff::2
zoop.boing 30 NS ns3
ns3 30 A 10.53.0.3
30 AAAA fd92:7065:b8e:ffff::3
ns4 30 A 10.53.0.4
30 AAAA fd92:7065:b8e:ffff::4
a.bit.longer.ns.name 1 A 10.53.0.4
1 AAAA fd92:7065:b8e:ffff::4
-1
View File
@@ -1 +0,0 @@
good.db
-15
View File
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 2 SOA ns2 hostmaster.stale. 1 2 3 4 5
@ 2 NS ns2
ns2 2 A 10.53.0.2
2 AAAA fd92:7065:b8e:ffff::2
-1
View File
@@ -1 +0,0 @@
good.db
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 30 SOA ns3.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns3.good.
1.1.1.1 60 NS ns4.good.
-15
View File
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns hostmaster.a.b.stale. 1 2 3 4 5
@ 1 NS ns
@ 1 TXT "peekaboo"
ns 1 A 10.53.0.3
+273 -34
View File
@@ -1,46 +1,285 @@
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
# 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.
SPDX-License-Identifier: MPL-2.0
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
"""
import dns.rcode
from isctest.asyncserver import AsyncDnsServer
from qmin_ans import DelayedResponseHandler, EntRcodeChanger, QueryLogHandler
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
class QueryLogger(QueryLogHandler):
domains = ["8.2.6.0.1.0.0.2.ip6.arpa.", "a.b.stale.", "zoop.boing.good."]
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
class ZoopBoingBadHandler(EntRcodeChanger):
domains = ["zoop.boing.bad."]
rcode = dns.rcode.NXDOMAIN
def endswith(domain, labels):
return domain.endswith("." + labels) or domain == labels
class ZoopBoingUglyHandler(EntRcodeChanger):
domains = ["zoop.boing.ugly."]
rcode = dns.rcode.FORMERR
############################################################################
# Respond to a DNS query.
# For good. it serves:
# zoop.boing.good. NS ns3.good.
# icky.ptang.zoop.boing.good. NS a.bit.longer.ns.name.good.
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 milliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage to non-empty terminals
#
# For stale. it serves:
# a.b.stale. IN TXT peekaboo (resolver did not do qname minimization)
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split(".")
suffix = ""
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
ugly = False
slow = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
ip6req = False
if endswith(lqname, "bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif endswith(lqname, "ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif endswith(lqname, "good."):
suffix = "good."
lqname = lqname[:-5]
elif endswith(lqname, "slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
elif endswith(lqname, "8.2.6.0.1.0.0.2.ip6.arpa."):
ip6req = True
elif endswith(lqname, "a.b.stale."):
if lqname == "a.b.stale.":
r.flags |= dns.flags.AA
if rrtype == TXT:
# Direct query.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "peekaboo"))
elif rrtype == NS:
# NS a.b.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.a.b.stale."))
r.additional.append(
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.3")
)
elif rrtype == SOA:
# SOA a.b.
r.answer.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
elif lqname == "ns.a.b.stale.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.3")
)
else:
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
else:
r.flags |= dns.flags.AA
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
r.set_rcode(NXDOMAIN)
# NXDOMAIN.
return r
else:
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
if lqname == "zoop.boing." and rrtype == NS:
r.answer.append(
dns.rrset.from_text(lqname + suffix, 1, IN, NS, "ns3." + suffix)
)
r.flags |= dns.flags.AA
elif endswith(lqname, "icky.ptang.zoop.boing."):
r.authority.append(
dns.rrset.from_text(
"icky.ptang.zoop.boing." + suffix,
1,
IN,
NS,
"a.bit.longer.ns.name." + suffix,
)
)
elif endswith("icky.ptang.zoop.boing.", lqname):
r.authority.append(
dns.rrset.from_text(
"zoop.boing." + suffix,
1,
IN,
SOA,
"ns3." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
if bad:
r.set_rcode(NXDOMAIN)
if ugly:
r.set_rcode(FORMERR)
elif endswith(lqname, "zoop.boing."):
r.authority.append(
dns.rrset.from_text(
"zoop.boing." + suffix,
1,
IN,
SOA,
"ns3." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
r.set_rcode(NXDOMAIN)
elif ip6req:
r.authority.append(
dns.rrset.from_text(
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, NS, "ns4.good."
)
)
r.additional.append(dns.rrset.from_text("ns4.good.", 60, IN, A, "10.53.0.4"))
else:
r.set_rcode(REFUSED)
if slow:
time.sleep(0.4)
return r
class ZoopBoingSlowHandler(DelayedResponseHandler):
domains = ["zoop.boing.slow."]
delay = 0.4
def sigterm(signum, frame):
print("Shutting down now...")
os.remove("ans.pid")
running = False
sys.exit(0)
if __name__ == "__main__":
server = AsyncDnsServer()
server.install_response_handler(QueryLogger())
server.install_response_handler(ZoopBoingBadHandler())
server.install_response_handler(ZoopBoingUglyHandler())
server.install_response_handler(ZoopBoingSlowHandler())
server.run()
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.3"
ip6 = "fd92:7065:b8e:ffff::3"
try:
port = int(os.environ["PORT"])
except:
port = 5300
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
f = open("ans.pid", "w")
pid = os.getpid()
print(pid, file=f)
f.close()
running = True
print("Listening on %s port %d" % (ip4, port))
if havev6:
print("Listening on %s port %d" % (ip6, port))
print("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print(
"Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
)
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break
@@ -1,14 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns3.bad. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.bad.
icky.ptang 1 NS a.bit.longer.ns.name.bad.
@@ -1,14 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns3.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.good.
icky.ptang 1 NS a.bit.longer.ns.name.good.
@@ -1,14 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns3.slow. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.slow.
icky.ptang 1 NS a.bit.longer.ns.name.slow.
@@ -1,14 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns3.ugly. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS ns3.ugly.
icky.ptang 1 NS a.bit.longer.ns.name.ugly.
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 30 SOA ns4.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 30 NS ns4.good.
test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4 1 TXT "long_ip6_name"
-15
View File
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns hostmaster.a.b.stale. 1 2 3 4 5
@ 1 NS ns
ns 1 A 10.53.0.4
@ 1 TXT "hooray"
+331 -79
View File
@@ -1,93 +1,345 @@
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
# 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.
SPDX-License-Identifier: MPL-2.0
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
"""
from typing import AsyncGenerator
import dns.rcode
from isctest.asyncserver import (
AsyncDnsServer,
DnsResponseSend,
DomainHandler,
QueryContext,
ResponseAction,
)
from qmin_ans import DelayedResponseHandler, EntRcodeChanger, QueryLogHandler, log_query
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
class QueryLogger(QueryLogHandler):
domains = [
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
"icky.ptang.zoop.boing.good.",
]
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
class StaleHandler(DomainHandler):
"""
The test code relies on this server returning non-minimal (i.e. including
address records in the ADDITIONAL section) responses to NS queries for
`b.stale` and `a.b.stale`. While this logic (returning non-minimal
responses to NS queries) could be implemented in AsyncDnsServer itself,
doing so breaks a lot of other checks in this system test. Therefore, only
these two zones behave in this particular way, thanks to a custom response
handler implemented below.
"""
domains = ["b.stale", "a.b.stale"]
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
if qctx.qtype == dns.rdatatype.NS:
assert qctx.zone
assert qctx.response.answer[0]
for nameserver in qctx.response.answer[0]:
if not nameserver.target.is_subdomain(qctx.response.answer[0].name):
continue
glue_a = qctx.zone.get_rrset(nameserver.target, dns.rdatatype.A)
if glue_a:
qctx.response.additional.append(glue_a)
glue_aaaa = qctx.zone.get_rrset(nameserver.target, dns.rdatatype.AAAA)
if glue_aaaa:
qctx.response.additional.append(glue_aaaa)
yield DnsResponseSend(qctx.response)
def endswith(domain, labels):
return domain.endswith("." + labels) or domain == labels
class IckyPtangZoopBoingBadHandler(EntRcodeChanger):
domains = ["icky.ptang.zoop.boing.bad."]
rcode = dns.rcode.NXDOMAIN
############################################################################
# Respond to a DNS query.
# For good. it serves:
# icky.ptang.zoop.boing.good. NS a.bit.longer.ns.name.
# icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.1
# more.icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.2
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 milliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage to non-empty terminals
#
# For stale. it serves:
# a.b.stale. IN TXT hooray (resolver did do qname minimization)
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split(".")
suffix = ""
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
slow = False
ugly = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
ip6req = False
if endswith(lqname, "bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif endswith(lqname, "ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif endswith(lqname, "good."):
suffix = "good."
lqname = lqname[:-5]
elif endswith(lqname, "slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
elif endswith(lqname, "1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."):
ip6req = True
elif endswith(lqname, "b.stale."):
if lqname == "a.b.stale.":
r.flags |= dns.flags.AA
if rrtype == TXT:
# Direct query.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "hooray"))
elif rrtype == NS:
# NS a.b.
# This is only returned if a query for b.stale/NS has been made
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.a.b.stale."))
r.additional.append(
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
)
elif rrtype == SOA:
# SOA a.b.
r.answer.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
elif lqname == "ns.a.b.stale.":
r.flags |= dns.flags.AA
if rrtype == A:
r.answer.append(
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"
)
)
elif lqname == "b.stale.":
r.flags |= dns.flags.AA
if rrtype == NS:
# NS b.
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.b.stale."))
r.additional.append(
dns.rrset.from_text("ns.b.stale.", 1, IN, A, "10.53.0.4")
)
elif rrtype == SOA:
# SOA b.
r.answer.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
elif lqname == "ns.b.stale.":
r.flags |= dns.flags.AA
if rrtype == A:
# SOA a.b.
r.answer.append(
dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.4")
)
else:
# NODATA.
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
else:
r.authority.append(
dns.rrset.from_text(
lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"
)
)
r.set_rcode(NXDOMAIN)
# NXDOMAIN.
return r
else:
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
if lqname == "icky.icky.icky.ptang.zoop.boing." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.1"))
r.flags |= dns.flags.AA
elif lqname == "more.icky.icky.icky.ptang.zoop.boing." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.2"))
r.flags |= dns.flags.AA
elif lqname == "icky.ptang.zoop.boing." and rrtype == NS:
r.answer.append(
dns.rrset.from_text(
lqname + suffix, 1, IN, NS, "a.bit.longer.ns.name." + suffix
)
)
r.flags |= dns.flags.AA
elif endswith(lqname, "icky.ptang.zoop.boing."):
r.authority.append(
dns.rrset.from_text(
"icky.ptang.zoop.boing." + suffix,
1,
IN,
SOA,
"ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1",
)
)
if bad or not endswith("more.icky.icky.icky.ptang.zoop.boing.", lqname):
r.set_rcode(NXDOMAIN)
if ugly:
r.set_rcode(FORMERR)
elif ip6req:
r.flags |= dns.flags.AA
if (
lqname
== "test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."
and rrtype == TXT
):
r.answer.append(
dns.rrset.from_text(
"test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
1,
IN,
TXT,
"long_ip6_name",
)
)
elif endswith(
"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
lqname,
):
# NODATA answer
r.authority.append(
dns.rrset.from_text(
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
60,
IN,
SOA,
"ns4.good. hostmaster.arpa. 2018050100 120 30 320 16",
)
)
else:
# NXDOMAIN
r.authority.append(
dns.rrset.from_text(
"1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.",
60,
IN,
SOA,
"ns4.good. hostmaster.arpa. 2018050100 120 30 320 16",
)
)
r.set_rcode(NXDOMAIN)
else:
r.set_rcode(REFUSED)
if slow:
time.sleep(0.4)
return r
class IckyPtangZoopBoingUglyHandler(EntRcodeChanger):
domains = ["icky.ptang.zoop.boing.ugly."]
rcode = dns.rcode.FORMERR
def sigterm(signum, frame):
print("Shutting down now...")
os.remove("ans.pid")
running = False
sys.exit(0)
class IckyPtangZoopBoingSlowHandler(DelayedResponseHandler):
domains = ["icky.ptang.zoop.boing.slow."]
delay = 0.4
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.4"
ip6 = "fd92:7065:b8e:ffff::4"
try:
port = int(os.environ["PORT"])
except:
port = 5300
if __name__ == "__main__":
server = AsyncDnsServer()
server.install_response_handler(QueryLogger())
server.install_response_handler(StaleHandler())
server.install_response_handler(IckyPtangZoopBoingBadHandler())
server.install_response_handler(IckyPtangZoopBoingUglyHandler())
server.install_response_handler(IckyPtangZoopBoingSlowHandler())
server.run()
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
f = open("ans.pid", "w")
pid = os.getpid()
print(pid, file=f)
f.close()
running = True
print("Listening on %s port %d" % (ip4, port))
if havev6:
print("Listening on %s port %d" % (ip6, port))
print("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print(
"Query received on %s" % (ip4 if s == query4_socket else ip6), end=" "
)
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break
-16
View File
@@ -1,16 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns hostmaster.b.stale. 1 2 3 4 5
@ 1 NS ns
ns 1 A 10.53.0.4
a 1 NS ns.a
ns.a 1 A 10.53.0.4
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns4.bad. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.bad.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns4.good. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.good.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns4.slow. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.slow.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
@@ -1,15 +0,0 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
@ 1 SOA ns4.ugly. hostmaster.arpa. 2018050100 1 1 1 1
@ 1 NS a.bit.longer.ns.name.ugly.
icky.icky 1 A 192.0.2.1
more.icky.icky 1 A 192.0.2.2
-107
View File
@@ -1,107 +0,0 @@
"""
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
SPDX-License-Identifier: MPL-2.0
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
"""
from typing import AsyncGenerator
import abc
import dns.rcode
import dns.rdataclass
import dns.rdatatype
from isctest.asyncserver import (
DnsResponseSend,
DomainHandler,
QueryContext,
ResponseAction,
)
from isctest.compat import dns_rcode
def log_query(qctx: QueryContext) -> None:
"""
Log a received DNS query to a text file inspected by `tests.sh`. AAAA and
A queries are logged identically because the relative order in which they
are received does not matter.
"""
qname = qctx.qname.to_text()
qtype = dns.rdatatype.to_text(qctx.qtype)
if qtype in ("A", "AAAA"):
qtype = "ADDR"
with open("query.log", "a", encoding="utf-8") as query_log:
print(f"{qtype} {qname}", file=query_log)
class QueryLogHandler(DomainHandler):
"""
Log all received DNS queries to a text file. Use the zone file for
preparing responses.
"""
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
yield DnsResponseSend(qctx.response)
class EntRcodeChanger(DomainHandler):
"""
Log all received DNS queries to a text file. Use the zone file for
preparing responses, but override the RCODE returned for empty
non-terminals (ENTs) to the value specified by the child class. This
emulates broken authoritative servers.
"""
@property
@abc.abstractmethod
def rcode(self) -> dns_rcode:
raise NotImplementedError
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
assert qctx.zone
log_query(qctx)
if (
qctx.response.rcode() == dns.rcode.NOERROR
and not qctx.response.answer
and qctx.response.authority
and qctx.response.authority[0].rdtype == dns.rdatatype.SOA
and not qctx.zone.get_node(qctx.qname)
):
qctx.response.set_rcode(self.rcode)
yield DnsResponseSend(qctx.response)
class DelayedResponseHandler(DomainHandler):
"""
Log all received DNS queries to a text file. Use the zone file for
preparing responses, but delay sending every answer by the amount of time
specified (in seconds) by the child class. This emulates network delays.
"""
@property
@abc.abstractmethod
def delay(self) -> float:
raise NotImplementedError
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[ResponseAction, None]:
log_query(qctx)
yield DnsResponseSend(qctx.response, delay=self.delay)
-20
View File
@@ -43,12 +43,6 @@ grep "status: NOERROR" dig.out.ns1.test${n} >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
rndccmd 10.53.0.1 stats || ret=1 # Get the responses, RTT and timeout statistics before the following timeout tests
grep -F 'responses received' ns1/named.stats >ns1/named.stats.responses-before || true
grep -F 'queries with RTT' ns1/named.stats >ns1/named.stats.rtt-before || true
grep -F 'query timeouts' ns1/named.stats >ns1/named.stats.timeouts-before || true
mv ns1/named.stats ns1/named.stats-before
# 'resolver-query-timeout' is set to 5 seconds in ns1, so dig with a lower
# timeout value should give up earlier than that.
n=$((n + 1))
@@ -72,20 +66,6 @@ grep -F "EDE: 22 (No Reachable Authority)" dig.out.ns1.test${n} >/dev/null || re
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "checking that the timeout didn't skew the resolver responses counters and did update the timeout counter ($n)"
ret=0
rndccmd 10.53.0.1 stats || ret=1
grep -F 'responses received' ns1/named.stats >ns1/named.stats.responses-after || true
grep -F 'queries with RTT' ns1/named.stats >ns1/named.stats.rtt-after || true
grep -F 'query timeouts' ns1/named.stats >ns1/named.stats.timeouts-after || true
mv ns1/named.stats ns1/named.stats-after
diff ns1/named.stats.responses-before ns1/named.stats.responses-after >/dev/null || ret=1
diff ns1/named.stats.rtt-before ns1/named.stats.rtt-after >/dev/null || ret=1
diff ns1/named.stats.timeouts-before ns1/named.stats.timeouts-after >/dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
# 'resolver-query-timeout' is set to 5 seconds in ns1, so named should
# interrupt the non-responsive query and send a SERVFAIL answer before dig's
# own timeout fires, which is set to 7 seconds. This time, exampleudp.net is
@@ -21,7 +21,6 @@ pytestmark = pytest.mark.extra_artifacts(
"nextpart.out.*",
"ans*/ans.run",
"ans*/query.log",
"ns1/named.stats*",
"ns4/tld.db",
"ns5/trusted.conf",
"ns6/K*",
+2 -3
View File
@@ -264,8 +264,7 @@ sub construct_ns_command {
foreach my $t_option(
"dropedns", "ednsformerr", "ednsnotimp", "ednsrefused",
"cookiealwaysvalid", "noaa", "noedns", "nosoa",
"maxudp512", "maxudp1460",
"noaa", "noedns", "nosoa", "maxudp512", "maxudp1460",
) {
if (-e "$testdir/$server/named.$t_option") {
$command .= "-T $t_option "
@@ -324,7 +323,7 @@ sub construct_ans_command {
}
if (-e "$testdir/$server/ans.py") {
$ENV{'PYTHONPATH'} = $testdir . ":" . $builddir;
$ENV{'PYTHONPATH'} = $testdir . ":" . $ENV{'srcdir'};
$command = "$PYTHON -u ans.py 10.53.0.$n $queryport";
} elsif (-e "$testdir/$server/ans.pl") {
$command = "$PERL ans.pl";
-1
View File
@@ -18,7 +18,6 @@ Changelog
development. Regular users should refer to :ref:`Release Notes <relnotes>`
for changes relevant to them.
.. include:: ../changelog/changelog-9.21.6.rst
.. include:: ../changelog/changelog-9.21.5.rst
.. include:: ../changelog/changelog-9.21.4.rst
.. include:: ../changelog/changelog-9.21.3.rst
-1
View File
@@ -218,7 +218,6 @@ latex_logo = "isc-logo.pdf"
linkcheck_timeout = 10
linkcheck_ignore = [
"http://127.0.0.1",
"https://dl.acm.org",
"https://gitlab.isc.org",
"https://kb.isc.org",
"https://simpleicon.com/",
-1
View File
@@ -47,7 +47,6 @@ The list of known issues affecting the latest version in the 9.21 branch can be
found at
https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.21
.. include:: ../notes/notes-9.21.6.rst
.. include:: ../notes/notes-9.21.5.rst
.. include:: ../notes/notes-9.21.4.rst
.. include:: ../notes/notes-9.21.3.rst
-478
View File
@@ -1,478 +0,0 @@
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
..
.. SPDX-License-Identifier: MPL-2.0
..
.. This Source Code Form is subject to the terms of the Mozilla Public
.. License, v. 2.0. If a copy of the MPL was not distributed with this
.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
..
.. See the COPYRIGHT file distributed with this work for additional
.. information regarding copyright ownership.
BIND 9.21.6
-----------
New Features
~~~~~~~~~~~~
- Implement the min-transfer-rate-in configuration option.
``a282f1ba3f``
A new option 'min-transfer-rate-in <bytes> <minutes>' has been added
to the view and zone configurations. It can abort incoming zone
transfers which run very slowly due to network related issues, for
example. The default value is set to 10240 bytes in 5 minutes.
:gl:`#3914` :gl:`!9098`
- Add digest methods for SIG and RRSIG. ``fd48df20f3``
ZONEMD digests RRSIG records and potentially digests SIG record. Add
digests methods for both record types. :gl:`#5219` :gl:`!10217`
- Add HTTPS record query to host command line tool. ``d34414c47b``
The host command was extended to also query for the HTTPS RR type by
default. :gl:`!8642`
Removed Features
~~~~~~~~~~~~~~~~
- Clean up unnecessary code in qpcache. ``74c9ff384e``
Removed some code from the cache database implementation that was left
over from before it and the zone database implementation were
separated. :gl:`!9991`
- Cleanup isc/util.h header and friends. ``239712df16``
Cleanup short list macros from <isc/util.h>, remove two unused
headers, move locking macros to respective headers and use only the
C11 static assertion. :gl:`!10196`
- Remove check for the mandatory IPv6 support. ``daa9c17905``
IPv6 Advanced Socket API (:rfc:`3542`) is a hard requirement, remove
the autoconf check to speed up the ./configure run a little bit.
:gl:`!10201`
- Remove log initialization checks from named. ``1b3e7f52ec``
Logging initialization check is now redundant as there is a default
global log context created during libisc's constructor.
`isc_log` calls can safely be made at any time outside libisc's
constructor. :gl:`!10186`
Feature Changes
~~~~~~~~~~~~~~~
- Refactor and simplify isc_symtab. ``5559539eb0``
This commit does several changes to isc_symtab:
1. Rewrite the isc_symtab to internally use isc_hashmap instead of
hand-stiched hashtable.
2. Create a new isc_symtab_define_and_return() api, which returns
the already defined symvalue on ISC_R_EXISTS; this allows users of
the API to skip the isc_symtab_lookup()+isc_symtab_define() calls
and directly call isc_symtab_define_and_return().
3. Merge isccc_symtab into isc_symtab - the only missing function
was isccc_symtab_foreach() that was merged into isc_symtab API.
4. Add full set of unit tests for the isc_symtab API. :gl:`#5103`
:gl:`!9921`
- Drop malformed notify messages early instead of decompressing them.
``7fce7707db``
The DNS header shows if a message has multiple questions or invalid
NOTIFY sections. We can drop these messages early, right after parsing
the question. This matches RFC 9619 for multi-question messages and
Unbound's handling of NOTIFY. We still parse the question to include
it in our FORMERR response.
Add drop_msg_early() function to check for these conditions: -
Messages with more than one question, as required by RFC 9619 - NOTIFY
query messages containing answer sections (like Unbound) - NOTIFY
messages containing authority sections (like Unbound) :gl:`#5158`,
#3656 :gl:`!10056`
- Cleanup parts of the isc_mem API. ``4ba1ccfa2e``
This MR changes custom attach/detach implementation with refcount
macros, replaces isc_mem_destroy() with isc_mem_detach(), and does
various small cleanups. :gl:`!9456`
- Move the library initialization and shutdown to executables.
``6e0c1f151c``
Instead of relying on unreliable order of execution of the library
constructors and destructors, move them to individual binaries. The
advantage is that the execution time and order will remain constant
and will not depend on the dynamic load dependency solver.
:gl:`!10069`
- Reduce memory used to store DNS names. ``24db1b1a8a``
The memory used to internally store the DNS names has been reduced.
:gl:`!10140`
- Unify fips handling to isc_crypto and make the toggle one way.
``3de629d6b7``
Since algorithm fetching is handled purely in libisc, FIPS mode
toggling can be purely done in within the library instead of provider
fetching in the binary for OpenSSL >=3.0.
Disabling FIPS mode isn't a realistic requirement and isn't done
anywhere in the codebase. Make the FIPS mode toggle enable-only to
reflect the situation. :gl:`!9920`
Bug Fixes
~~~~~~~~~
- Prevent a reference leak when using plugins. ``5604d3a44e``
The `NS_QUERY_DONE_BEGIN` and `NS_QUERY_DONE_SEND` plugin hooks could
cause a reference leak if they returned `NS_HOOK_RETURN` without
cleaning up the query context properly. :gl:`#2094` :gl:`!9971`
- Fix isc_quota bug. ``742d379d88``
Running jobs which were entered into the isc_quota queue is the
responsibility of the isc_quota_release() function, which, when
releasing a previously acquired quota, checks whether the queue is
empty, and if it's not, it runs a job from the queue without touching
the 'quota->used' counter. This mechanism is susceptible to a possible
hangup of a newly queued job in case when between the time a decision
has been made to queue it (because used >= max) and the time it was
actually queued, the last quota was released. Since there is no more
quotas to be released (unless arriving in the future), the newly
entered job will be stuck in the queue.
Fix the issue by adding checks in both isc_quota_release() and
isc_quota_acquire_cb() to make sure that the described hangup does not
happen. Also see code comments. :gl:`#4965` :gl:`!10082`
- Fix dual-stack-servers configuration option. ``6af708f3b0``
The dual-stack-servers configuration option was not working as
expected; the specified servers were not being used when they should
have been, leading to resolution failures. This has been fixed.
:gl:`#5019` :gl:`!9708`
- Implement sig0key-checks-limit and sig0message-checks-limit.
``d78ebff861``
Previously a hard-coded limitation of maximum two key or message
verification checks were introduced when checking the message's SIG(0)
signature. It was done in order to protect against possible DoS
attacks. The logic behind choosing the number 2 was that more than a
single key should only be required during key rotations, and in that
case two keys are enough. But later it became apparent that there are
other use cases too where even more keys are required, see issue
number #5050 in GitLab.
This change introduces two new configuration options for the views,
`sig0key-checks-limit` and `sig0message-checks-limit`, which define
how many keys are allowed to be checked to find a matching key, and
how many message verifications are allowed to take place once a
matching key has been found. The latter protects against expensive
cryptographic operations when there are keys with colliding tags and
algorithm numbers, with default being 2, and the former protects
against a bit less expensive key parsing operations and defaults to
16. :gl:`#5050` :gl:`!9967`
- Fix the data race causing a permanent active client increase.
``479c366c2b``
Previously, a data race could cause a newly created fetch context for
a new client to be used before it had been fully initialized, which
would cause the query to become stuck; queries for the same data would
be either paused indefinitely or dropped because of the
`clients-per-query` limit. This has been fixed. :gl:`#5053`
:gl:`!10146`
- Fix deferred validation of unsigned DS and DNSKEY records.
``ebf1606f38``
When processing a query with the "checking disabled" bit set (CD=1),
`named` stores the unvalidated result in the cache, marked "pending".
When the same query is sent with CD=0, the cached data is validated,
and either accepted as an answer, or ejected from the cache as
invalid. This deferred validation was not attempted for DS and DNSKEY
records if they had no cached signatures, causing spurious validation
failures. We now complete the deferred validation in this scenario.
Also, if deferred validation fails, we now re-query the data to find
out whether the zone has been corrected since the invalid data was
cached. :gl:`#5066` :gl:`!10104`
- When recording an rr trace, use libtool. ``6320586df0``
When a system test is run with the `USE_RR` environment variable set
to 1, an `rr` trace is now correctly generated for each instance of
`named`. :gl:`#5079` :gl:`!10197`
- Do not cache signatures for rejected data. ``fc3a4d6f89``
The cache has been updated so that if new data is rejected - for
example, because there was already existing data at a higher trust
level - then its covering RRSIG will also be rejected. :gl:`#5132`
:gl:`!9999`
- Fix wrong logging severity in do_nsfetch() ``1f6a16e6d0``
ISC_LOG_WARNING was used while ISC_LOG_DEBUG(3) was implied.
:gl:`#5145` :gl:`!10017`
- Fix RPZ race condition during a reconfiguration. ``5ba811bea2``
With RPZ in use, `named` could terminate unexpectedly because of a
race condition when a reconfiguration command was received using
`rndc`. This has been fixed. :gl:`#5146` :gl:`!10079`
- "CNAME and other data check" not applied to all types. ``b694acbe45``
An incorrect optimization caused "CNAME and other data" errors not to
be detected if certain types were at the same node as a CNAME. This
has been fixed. :gl:`#5150` :gl:`!10033`
- Use named Service Parameter Keys (SvcParamKeys) by default.
``3f61a87be3``
When converting SVCB records to text representation `named` now uses
named `SvcParamKeys` values unless backward-compatible mode is
activated, in which case the values which were not defined initially
in RFC9460 and were added later (see [1]) are converted to opaque
"keyNNNN" syntax, like, for example, "key7" instead of "dohpath".
Also a new `+[no]svcparamkeycompat` option is implemented for `dig`,
which enables the backward-compatible mode and uses the opaque syntax,
if required for interoperability with other software or scripts. By
default, the compatibility mode is disabled.
[1] https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
:gl:`#5156` :gl:`!10085`
- Relax private DNSKEY and RRSIG constraints. ``1bc7016d7a``
DNSKEY, KEY, RRSIG and SIG constraints have been relaxed to allow
empty key and signature material after the algorithm identifier for
PRIVATEOID and PRIVATEDNS. It is arguable whether this falls within
the expected use of these types as no key material is shared and the
signatures are ineffective but these are private algorithms and they
can be totally insecure. :gl:`#5167` :gl:`!10083`
- Delete dead nodes when committing a new version. ``67255da4b3``
In the qpzone implementation of `dns_db_closeversion()`, if there are
changed nodes that have no remaining data, delete them. :gl:`#5169`
:gl:`!10089`
- Revert "Delete dead nodes when committing a new version"
``b652d5327c``
This reverts commit 67255da4b376f65138b299dcd5eb6a3b7f9735a9,
reversing changes made to 74c9ff384e695d1b27fa365d1fee84576f869d4c.
:gl:`#5169` :gl:`!10224`
- Fix dns_qp_insert() checks in qpzone. ``d6b63210a8``
Remove code in the QP zone database to handle failures of
`dns_qp_insert()` which can't actually happen. :gl:`#5171`
:gl:`!10088`
- Remove NSEC/DS/NSEC3 RRSIG check from dns_message_parse.
``f0785fedf1``
Previously, when parsing responses, named incorrectly rejected
responses without matching RRSIG records for NSEC/DS/NSEC3 records in
the authority section. This rejection, if appropriate, should have
been left for the validator to determine and has been fixed.
:gl:`#5185` :gl:`!10125`
- Fix TTL issue with ANY queries processed through RPZ "passthru"
``23c1fbc609``
Answers to an "ANY" query which were processed by the RPZ "passthru"
policy had the response-policy's `max-policy-ttl` value unexpectedly
applied. This has been fixed. :gl:`#5187` :gl:`!10176`
- Save time when creating a slab from another slab. ``cf981ab13b``
The `dns_rdataslab_fromrdataset()` function creates a slab from an
rdataset. If the source rdataset already uses a slab, then no
processing is necessary; we can just copy the existing slab to a new
location. :gl:`#5188` :gl:`!10162`
- Dnssec-signzone needs to check for a NULL key when setting offline.
``26f8ee7229``
dnssec-signzone could dereference a NULL key pointer when resigning a
zone. This has been fixed. :gl:`#5192` :gl:`!10161`
- Acquire the database reference before possibly last node release.
``c4868b5bd9``
Acquire the database reference in the detachnode() to prevent the last
reference to be release while the NODE_LOCK being locked. The
NODE_LOCK is locked/unlocked inside the RCU critical section, thus it
is most probably this should not pose a problem as the database uses
call_rcu memory reclamation, but this it is still safer to acquire the
reference before releasing the node. :gl:`#5194` :gl:`!10155`
- Fix a logic error in cache_name() ``02ef8ff01c``
A change in 6aba56ae8 (checking whether a rejected RRset was identical
to the data it would have replaced, so that we could still cache a
signature) inadvertently introduced cases where processing of a
response would continue when previously it would have been skipped.
:gl:`#5197` :gl:`!10157`
- Fix a bug in the statistics channel when querying zone transfers
information. ``e02d73e7e3``
When querying zone transfers information from the statistics channel
there was a rare possibility that `named` could terminate unexpectedly
if a zone transfer was in a state when transferring from all the
available primary servers had failed earlier. This has been fixed.
:gl:`#5198` :gl:`!10182`
- Fix assertion failure when dumping recursing clients. ``796b662b92``
Previously, if a new counter was added to the hashtable while dumping
recursing clients via the `rndc recursing` command, and
`fetches-per-zone` was enabled, an assertion failure could occur. This
has been fixed. :gl:`#5200` :gl:`!10164`
- Validating ADB fetches could cause a crash in import_rdataset()
``49ccbe857a``
Previously, in some cases, the resolver could return rdatasets of type
CNAME or DNAME without the result code being set to `DNS_R_CNAME` or
`DNS_R_DNAME`. This could trigger an assertion failure in the ADB. The
resolver error has been fixed. :gl:`#5201` :gl:`!10172`
- Call isc__iterated_hash_initialize in isc__work_cb. ``f3458fdf43``
isc_iterated_hash didn't work in offloaded threads as the per thread
initialisation has not been done. This has been fixed. :gl:`#5214`
:gl:`!10206`
- Fix a bug in get_request_transport_type() ``db5166ab99``
When `dns_remote_done()` is true, calling `dns_remote_curraddr()`
asserts. Add a `dns_remote_curraddr()` check before calling
`dns_remote_curraddr()`. :gl:`#5215` :gl:`!10222`
- Clean up dns_rdataslab module. ``948f8d7a98``
Rdata slabs used in the QP databases are usually prepended with a slab
header, but are sometimes "raw", containing only the rdata and no
header. Previously, to allow for them to be used both ways, functions
that operated on them took a `reservelen` argument, which would be set
to either the header length or to zero, and skipped over that many
bytes at the beginning of the buffer. Most such functions were never
used on the raw form. To make the code clearer, each of these
functions now operates on full slabs with headers, and an alternate
"raw" version of the function has been added in cases where that was
needed.
In addition, the `dns_rdataslab_merge()` and `_subtract()` functions
have been rewritten for clarity and efficiency, and a minor bug has
been fixed in `dns_rdataslab_equal()` and `_equalx()`, which could
cause an incorrect result if both slabs being compared had zero
length. :gl:`!10084`
- Dump the active resolver fetches from dns_resolver_dumpfetches()
``5d0c347e75``
Previously, active resolver fetches were only dumped when the
`fetches-per-zone` configuration option was enabled. Now, active
resolver fetches are dumped along with the number of
`clients-per-server` counters per resolver fetch. :gl:`!10107`
- Fix the foundname vs dcname madness in qpcache_findzonecut()
``4e68dbf194``
The qpcache_findzonecut() accepts two "foundnames": 'foundname' and
'dcname' could be NULL. Originally, when 'dcname' would be NULL, the
'dcname' would be set to 'foundname' which basically means that we
were copying the .ndata over itself for no apparent reason.
:gl:`!10049`
- Post [CVE-2024-12705] Performance Drop Fixes, Part 2. ``c8104daf8d``
This merge request addresses several key performance bottlenecks in
the DoH (DNS over HTTPS) implementation by introducing significant
optimizations and improvements.
### Key Improvements
1. **Simplification and Optimisation of `http_do_bio()` Function**:
- The code flow in the `http_do_bio()` function has been significantly
simplified. 2. **Flushing HTTP Write Buffer on Outgoing DNS
Messages**: - The buffer is flushed and a send operation is
performed when there is an outgoing DNS message. 3. **Bumping Active
Streams Processing Limit**: - The total number of active streams
has been increased to 60% of the total streams limit.
These changes collectively enhance the performance and reliability of
the DoH implementation, making it more efficient and robust for
handling high-load scenarios, particularly noticeable in long runs (>=
1h) of `stress:long:rpz:doh+udp:linux:*` tests. It improves perf. for
tests for BIND 9.18, but it likely will have a positive but less
pronounced effect on newer versions as well.
In essence, the merge request fixes three bottlenecks stacked upon
each other.
*It is a logical continuation of the merge requests !10109.* !10109,
unfortunately, did not completely [address the performance drop in
9.18](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/221545)
for longer runs of the stress test. This merge request [addresses
that](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/223661).
**P.S.**
The origin of the fixes is, in fact, the branch in !10193. So this MR
is a ... *forward port* of them. :gl:`!10192`
- Post [CVE-2024-12705] Performance Drop Fixes. ``3033d127d2``
This merge request fixes a [performance
drop](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/216728)
after merging the fixes for #4795, in particular in 9.18.
The MR [fixes the
problem](https://gitlab.isc.org/isc-projects/bind9/-/pipelines/219825)
without affecting performance for the newer versions, in particular
for [the development version](https://gitlab.isc.org/isc-projects/bind
9/-/pipelines/220619). :gl:`!10109`
- Remove 'target' from dns_adb. ``764eb65cf6``
When a server name turns out to be a CNAME or DNAME, the ADB does not
use it, but the `dns_adbname` structure still stored a copy of the
target name. This is unnecessary and the code has been removed.
:gl:`!10149`
- Simplify some dns_name API calls. ``e16560a650``
Several functions in the `dns_name` module have had parameters
removed, that were rarely or never used: - `dns_name_fromtext()` and
`dns_name_concatenate()` no longer take a target buffer. -
`dns_name_towire()` no longer takes a compression offset pointer; this
is now part of the compression context. - `dns_name_towire()` with a
`NULL` compression context will copy name data directly into a buffer
with no processing. :gl:`!10152`
- Sync the TSAN CC, CFLAGS and LDFLAGS in the respdiff:tsan job.
``22b5442722``
:gl:`!10209`
-186
View File
@@ -1,186 +0,0 @@
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
..
.. SPDX-License-Identifier: MPL-2.0
..
.. This Source Code Form is subject to the terms of the Mozilla Public
.. License, v. 2.0. If a copy of the MPL was not distributed with this
.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
..
.. See the COPYRIGHT file distributed with this work for additional
.. information regarding copyright ownership.
Notes for BIND 9.21.6
---------------------
New Features
~~~~~~~~~~~~
- Implement the :any:`min-transfer-rate-in` configuration option.
A new option :any:`min-transfer-rate-in` has been added
to the view and zone configurations. It can abort incoming zone
transfers that run very slowly due to network-related issues, for
example. The default value is 10240 bytes in five minutes.
:gl:`#3914`
- Add HTTPS record query to :iscman:`host` command line tool.
The :iscman:`host` command was extended to also query for the HTTPS RR
type by default.
- Implement :any:`sig0key-checks-limit` and :any:`sig0message-checks-limit`.
Previously, a hard-coded limitation of a maximum of two key or message
verification checks was introduced when checking a message's ``SIG(0)``
signature, to protect against possible DoS
attacks. Two as a maximum was chosen so that more than a
single key should only be required during key rotations, and in that
case two keys are enough. It later became apparent that there are
other use cases where even more keys are required; see the related GitLab issue for examples.
This change introduces two new configuration options for the views:
:any:`sig0key-checks-limit` and :any:`sig0message-checks-limit`. They define
how many keys can be checked to find a matching key, and
how many message verifications are allowed to take place once a
matching key has been found. The former provides
slightly less "expensive" key parsing operations and defaults to
16. The latter protects against expensive
cryptographic operations when there are keys with colliding tags and
algorithm numbers; the default is 2. :gl:`#5050`
Feature Changes
~~~~~~~~~~~~~~~
- Drop malformed notify messages early instead of decompressing them.
The DNS header shows whether a message has multiple questions or invalid
NOTIFY sections. :iscman:`named` can now drop these messages early, right after parsing
the question, to match :rfc:`9619` for multi-question messages and
Unbound's handling of NOTIFY. Questions are still parsed to be included
in BIND's FORMERR response.
Add ``drop_msg_early()`` function to check for these conditions:
- Messages with more than one question, as required by :rfc:`9619`
- NOTIFY query messages containing answer sections (like Unbound)
:gl:`#5158`
- Reduce memory used to store DNS names.
The memory used to internally store the DNS names has been reduced
by no longer caching certain fields from an internal data structure.
Bug Fixes
~~~~~~~~~
- Fix :any:`dual-stack-servers` configuration option.
The :any:`dual-stack-servers` configuration option was not working as
expected; the specified servers were not being used when they should
have been, leading to resolution failures. This has been fixed.
:gl:`#5019`
- Fix a data race causing a permanent active client increase.
Previously, a data race could cause a newly created fetch context for
a new client to be used before it had been fully initialized, which
would cause the query to become stuck; queries for the same data would
be either paused indefinitely or dropped because of the
:any:`clients-per-query` limit. This has been fixed. :gl:`#5053`
- Fix deferred validation of unsigned DS and DNSKEY records.
When processing a query with the "checking disabled" bit set (CD=1),
:iscman:`named` stores the invalidated result in the cache, marked "pending".
When the same query is sent with CD=0, the cached data is validated
and either accepted as an answer, or ejected from the cache as
invalid. This deferred validation was not attempted for DS and DNSKEY
records if they had no cached signatures, causing spurious validation
failures. The deferred validation is now completed in this scenario.
Also, if deferred validation fails, the data is now re-queried to find
out whether the zone has been corrected since the invalid data was
cached. :gl:`#5066`
- Fix RPZ race condition during a reconfiguration.
With RPZ in use, :iscman:`named` could terminate unexpectedly because of a
race condition when a reconfiguration command was received using
:iscman:`rndc`. This has been fixed. :gl:`#5146`
- "CNAME and other data check" not applied to all types.
An incorrect optimization caused "CNAME and other data" errors not to
be detected if certain types were at the same node as a CNAME. This
has been fixed. :gl:`#5150`
- Use named Service Parameter Keys (``SvcParamKeys``) by default.
When converting SVCB records to text representation, :iscman:`named` now uses
named ``SvcParamKeys`` values unless backward-compatible mode is
activated. In that case, values which were not defined initially
in :rfc:`9460` and were added later (see [1]) are converted to opaque
"keyNNNN" syntax, e.g. "key7" instead of "dohpath".
Also a new ``+[no]svcparamkeycompat`` option is implemented for :iscman:`dig`,
which enables the backward-compatible mode and uses the opaque syntax,
if required for interoperability with other software or scripts. By
default, the compatibility mode is disabled.
[1] https://www.iana.org/assignments/dns-svcb/dns-svcb.xhtml
:gl:`#5156`
- Relax private DNSKEY and RRSIG constraints.
DNSKEY, KEY, RRSIG, and SIG constraints have been relaxed to allow
empty key and signature material after the algorithm identifier for
PRIVATEOID and PRIVATEDNS. It is arguable whether this falls within
the expected use of these types, as no key material is shared and the
signatures are ineffective, but these are private algorithms and they
can be totally insecure. :gl:`#5167`
- Remove NSEC/DS/NSEC3 RRSIG check from ``dns_message_parse()``.
Previously, when parsing responses, :iscman:`named` incorrectly rejected
responses without matching RRSIG records for NSEC/DS/NSEC3 records in
the authority section. This rejection, if appropriate, should have
been left for the validator to determine and has been fixed.
:gl:`#5185`
- Fix TTL issue with ANY queries processed through RPZ "passthru".
Answers to an "ANY" query which were processed by the RPZ "passthru"
policy had the response-policy's ``max-policy-ttl`` value unexpectedly
applied. This has been fixed. :gl:`#5187`
- :iscman:`dnssec-signzone` needs to check for a NULL key when setting offline.
:iscman:`dnssec-signzone` could dereference a NULL key pointer when resigning
a zone. This has been fixed. :gl:`#5192`
- Fix a bug in the statistics channel when querying zone transfer
information.
When querying zone transfer information from the statistics channel,
there was a rare possibility that :iscman:`named` could terminate unexpectedly
if a zone transfer was in a state when transferring from all the
available primary servers had failed earlier. This has been fixed.
:gl:`#5198`
- Fix assertion failure when dumping recursing clients.
Previously, if a new counter was added to the hash table while dumping
recursing clients via the :option:`rndc recursing` command, and
:any:`fetches-per-zone` was enabled, an assertion failure could occur. This
has been fixed. :gl:`#5200`
- Dump the active resolver fetches from ``dns_resolver_dumpfetches()``
Previously, active resolver fetches were only dumped when the
:any:`fetches-per-zone` configuration option was enabled. Now, active
resolver fetches are dumped along with the number of
:any:`clients-per-query` counters per resolver fetch.
+2
View File
@@ -136,6 +136,7 @@ libdns_la_HEADERS = \
include/dns/view.h \
include/dns/xfrin.h \
include/dns/zone.h \
include/dns/zonekey.h \
include/dns/zoneverify.h \
include/dns/zt.h
@@ -254,6 +255,7 @@ libdns_la_SOURCES = \
zone.c \
zone_p.h \
zoneverify.c \
zonekey.c \
zt.c
if HAVE_GSSAPI
+5 -5
View File
@@ -1076,11 +1076,11 @@ new_adbfetch(dns_adb_t *adb) {
dns_adbfetch_t *fetch = NULL;
fetch = isc_mem_get(adb->hmctx, sizeof(*fetch));
*fetch = (dns_adbfetch_t){
.magic = DNS_ADBFETCH_MAGIC,
};
*fetch = (dns_adbfetch_t){ 0 };
dns_rdataset_init(&fetch->rdataset);
fetch->magic = DNS_ADBFETCH_MAGIC;
return fetch;
}
@@ -2909,7 +2909,6 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, bool no_validation,
* createfetch to find deepest cached name when we're providing
* domain and nameservers.
*/
dns_adbname_ref(adbname);
result = dns_resolver_createfetch(
adb->res, adbname->name, type, name, nameservers, NULL, NULL, 0,
options, depth, qc, gqc, isc_loop(), fetch_callback, adbname,
@@ -2917,10 +2916,11 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, bool no_validation,
if (result != ISC_R_SUCCESS) {
DP(ENTER_LEVEL, "fetch_name: createfetch failed with %s",
isc_result_totext(result));
dns_adbname_unref(adbname);
goto cleanup;
}
dns_adbname_ref(adbname);
if (type == dns_rdatatype_a) {
adbname->fetch_a = fetch;
inc_resstats(adb, dns_resstatscounter_gluefetchv4);
-35
View File
@@ -1101,41 +1101,6 @@ dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
return false;
}
bool
dns_dnssec_iszonekey(dns_rdata_dnskey_t *key) {
return (key->flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
(key->flags & DNS_KEYTYPE_NOAUTH) == 0 &&
(key->protocol == DNS_KEYPROTO_DNSSEC ||
key->protocol == DNS_KEYPROTO_ANY);
}
bool
dns_dnssec_haszonekey(dns_rdataset_t *keyset) {
isc_result_t result;
REQUIRE(keyset != NULL);
if (keyset->type != dns_rdatatype_dnskey) {
return false;
}
for (result = dns_rdataset_first(keyset); result == ISC_R_SUCCESS;
result = dns_rdataset_next(keyset))
{
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_dnskey_t key;
dns_rdataset_current(keyset, &rdata);
dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
if (dns_dnssec_iszonekey(&key)) {
return true;
}
}
return false;
}
void
dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
dns_dnsseckey_t **dkp) {
+19 -8
View File
@@ -162,7 +162,8 @@ computeid(dst_key_t *key);
static isc_result_t
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
unsigned int protocol, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
dst_key_t **keyp);
static isc_result_t
algorithm_status(unsigned int alg);
@@ -720,6 +721,13 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
isc_result_t
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
return dst_key_fromdns_ex(name, rdclass, source, mctx, false, keyp);
}
isc_result_t
dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
dst_key_t **keyp) {
uint8_t alg, proto;
uint32_t flags, extflags;
dst_key_t *key = NULL;
@@ -748,7 +756,7 @@ dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
}
result = frombuffer(name, alg, flags, proto, rdclass, source, mctx,
&key);
no_rdata, &key);
if (result != ISC_R_SUCCESS) {
return result;
}
@@ -767,7 +775,7 @@ dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
isc_result_t result;
result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx,
&key);
false, &key);
if (result != ISC_R_SUCCESS) {
return result;
}
@@ -2259,7 +2267,8 @@ computeid(dst_key_t *key) {
static isc_result_t
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
unsigned int protocol, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
dst_key_t **keyp) {
dst_key_t *key;
isc_result_t ret;
@@ -2281,10 +2290,12 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
return DST_R_UNSUPPORTEDALG;
}
ret = key->func->fromdns(key, source);
if (ret != ISC_R_SUCCESS) {
dst_key_free(&key);
return ret;
if (!no_rdata) {
ret = key->func->fromdns(key, source);
if (ret != ISC_R_SUCCESS) {
dst_key_free(&key);
return ret;
}
}
}
-18
View File
@@ -242,24 +242,6 @@ dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
* rrset. dns_dnssec_signs() works on any rrset.
*/
bool
dns_dnssec_iszonekey(dns_rdata_dnskey_t *key);
/*%<
* Verify that 'key' is a DNSSEC key with the DNS_KEYOWNER_ZONE flag set.
*
* Requires:
*\li 'key' is not NULL.
*/
bool
dns_dnssec_haszonekey(dns_rdataset_t *keyset);
/*%<
* Verify that 'keyset' includes at least one zone key.
*
* Requires:
*\li 'keyset' is not NULL.
*/
void
dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
dns_dnsseckey_t **dkp);
+5 -14
View File
@@ -205,9 +205,9 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
*\li Any other result indicates an error.
*/
isc_result_t
bool
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
dns_name_t *foundname, bool *wantdnssecp);
dns_name_t *foundname);
/*%<
* Is 'name' at or beneath a trusted key?
*
@@ -219,20 +219,11 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
*
*\li 'foundanme' is NULL or is a pointer to an initialized dns_name_t
*
*\li '*wantsdnssecp' is a valid bool.
*
* Ensures:
*
*\li On success, *wantsdnssecp will be true if and only if 'name'
* is at or beneath a trusted key. If 'foundname' is not NULL, then
* it will be updated to contain the name of the closest enclosing
* trust anchor.
*
* Returns:
*
*\li ISC_R_SUCCESS
*
*\li Any other result is an error.
*\li Returns true if and only if 'name' is at or beneath a trusted key.
* If 'foundname' is not NULL, then it will be updated to contain
* the name of the closest enclosing trust anchor.
*/
isc_result_t
+9 -11
View File
@@ -54,26 +54,24 @@
isc_result_t
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, dns_rdataset_t *addedrdataset);
isc_result_t
dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
dns_dbnode_t *node, dns_rdatatype_t covers,
isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
bool optout, dns_rdataset_t *addedrdataset);
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset);
/*%<
* Convert the authority data from 'message' into a negative cache
* rdataset, and store it in 'cache' at 'node' with a TTL limited to
* 'maxttl'.
*
* \li dns_ncache_add produces a negative cache entry with a trust of no
* more than answer
* \li dns_ncache_addoptout produces a negative cache entry which will have
* a trust of secure if all the records that make up the entry are secure.
* \li If 'secure' is true and all the records that make up the entry
* are secure, then dns_ncache_add produces a negative cache entry
* with trust level secure.
* \li If 'secure' is false, the negative cache entry's trust level
* will be capped at answer.
*
* The 'covers' argument is the RR type whose nonexistence we are caching,
* or dns_rdatatype_any when caching a NXDOMAIN response.
*
* 'optout' indicates a DNS_RDATASETATTR_OPTOUT should be set.
* 'optout' indicates DNS_RDATASETATTR_OPTOUT should be set. This only
* applies in secure zones; if 'secure' is false, 'optout' is ignored.
*
* Note:
*\li If 'addedrdataset' is not NULL, then it will be attached to the added
+27
View File
@@ -689,3 +689,30 @@ dns_rdataset_equals(const dns_rdataset_t *rdataset1,
* \li 'rdataset1' is a valid rdataset.
* \li 'rdataset2' is a valid rdataset.
*/
/*%
* Returns true if the rdataset is of type 'type', or type RRSIG
* and covers 'type'.
*/
static inline bool
dns_rdataset_matchestype(const dns_rdataset_t *rdataset,
const dns_rdatatype_t type) {
REQUIRE(DNS_RDATASET_VALID(rdataset));
return rdataset->type == type ||
(rdataset->type == dns_rdatatype_rrsig &&
rdataset->covers == type);
}
/*%
* Returns true if the rdataset is of type 'type', or type RRSIG
* and covers 'type'.
*/
static inline bool
dns_rdataset_issigtype(const dns_rdataset_t *rdataset,
const dns_rdatatype_t type) {
REQUIRE(DNS_RDATASET_VALID(rdataset));
return rdataset->type == dns_rdatatype_rrsig &&
rdataset->covers == type;
}
+3 -3
View File
@@ -151,8 +151,8 @@ struct dns_validator {
uint8_t unsupported_digest;
dns_rdata_t rdata;
bool resume;
isc_counter_t *nvalidations;
isc_counter_t *nfails;
uint32_t *nvalidations;
uint32_t *nfails;
isc_counter_t *qc;
isc_counter_t *gqc;
@@ -172,7 +172,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
isc_loop_t *loop, isc_job_cb cb, void *arg,
isc_counter_t *nvalidations, isc_counter_t *nfails,
uint32_t *nvalidations, uint32_t *nfails,
isc_counter_t *qc, isc_counter_t *gqc,
dns_edectx_t *edectx, dns_validator_t **validatorp);
/*%<
+3 -8
View File
@@ -986,13 +986,12 @@ dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp);
*\li ISC_R_NOTFOUND
*/
isc_result_t
bool
dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
isc_stdtime_t now, bool checknta, bool *ntap,
bool *secure_domain);
isc_stdtime_t now, bool checknta, bool *ntap);
/*%<
* Is 'name' at or beneath a trusted key, and not covered by a valid
* negative trust anchor? Put answer in '*secure_domain'.
* negative trust anchor, and DNSSEC validation is enabled?
*
* If 'checknta' is false, ignore the NTA table in determining
* whether this is a secure domain. If 'checknta' is not false, and if
@@ -1001,10 +1000,6 @@ dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
*
* Requires:
* \li 'view' is valid.
*
* Returns:
*\li ISC_R_SUCCESS
*\li Any other value indicates failure
*/
bool
+41 -30
View File
@@ -818,7 +818,7 @@ dns_zone_setmaxretrytime(dns_zone_t *zone, uint32_t val);
* val > 0.
*/
void
isc_result_t
dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
/*%<
* Set the source address to be used in IPv4 zone transfers.
@@ -826,20 +826,22 @@ dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
* Require:
*\li 'zone' to be a valid zone.
*\li 'xfrsource' to contain the address.
*
* Returns:
*\li #ISC_R_SUCCESS
*/
void
dns_zone_getxfrsource4(dns_zone_t *zone, isc_sockaddr_t *xfrsource);
isc_sockaddr_t *
dns_zone_getxfrsource4(dns_zone_t *zone);
/*%<
* Returns the source address set by a previous dns_zone_setxfrsource4
* call, or the default of inaddr_any, port 0.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'xfrsource' to not be NULL
*/
void
isc_result_t
dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
/*%<
* Set the source address to be used in IPv6 zone transfers.
@@ -847,20 +849,22 @@ dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource);
* Require:
*\li 'zone' to be a valid zone.
*\li 'xfrsource' to contain the address.
*
* Returns:
*\li #ISC_R_SUCCESS
*/
void
dns_zone_getxfrsource6(dns_zone_t *zone, isc_sockaddr_t *xfrsource);
isc_sockaddr_t *
dns_zone_getxfrsource6(dns_zone_t *zone);
/*%<
* Returns the source address set by a previous dns_zone_setxfrsource6
* call, or the default of in6addr_any, port 0.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'xfrsource' to not be NULL
*/
void
isc_result_t
dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
/*%<
* Set the source address to be used with IPv4 parental DS queries.
@@ -868,20 +872,22 @@ dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
* Require:
*\li 'zone' to be a valid zone.
*\li 'parentalsrc' to contain the address.
*
* Returns:
*\li #ISC_R_SUCCESS
*/
void
dns_zone_getparentalsrc4(dns_zone_t *zone, isc_sockaddr_t *parentalsrc);
isc_sockaddr_t *
dns_zone_getparentalsrc4(dns_zone_t *zone);
/*%<
* Returns the source address set by a previous dns_zone_setparentalsrc4
* call, or the default of inaddr_any, port 0.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'parentalsrc' to be non NULL.
*/
void
isc_result_t
dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
/*%<
* Set the source address to be used with IPv6 parental DS queries.
@@ -889,20 +895,22 @@ dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc);
* Require:
*\li 'zone' to be a valid zone.
*\li 'parentalsrc' to contain the address.
*
* Returns:
*\li #ISC_R_SUCCESS
*/
void
dns_zone_getparentalsrc6(dns_zone_t *zone, isc_sockaddr_t *parentalsrc);
isc_sockaddr_t *
dns_zone_getparentalsrc6(dns_zone_t *zone);
/*%<
* Returns the source address set by a previous dns_zone_setparentalsrc6
* call, or the default of in6addr_any, port 0.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'parentalsrc' to be non NULL.
*/
void
isc_result_t
dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
/*%<
* Set the source address to be used with IPv4 NOTIFY messages.
@@ -910,20 +918,22 @@ dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
* Require:
*\li 'zone' to be a valid zone.
*\li 'notifysrc' to contain the address.
*
* Returns:
*\li #ISC_R_SUCCESS
*/
void
dns_zone_getnotifysrc4(dns_zone_t *zone, isc_sockaddr_t *notifysrc);
isc_sockaddr_t *
dns_zone_getnotifysrc4(dns_zone_t *zone);
/*%<
* Returns the source address set by a previous dns_zone_setnotifysrc4
* call, or the default of inaddr_any, port 0.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'notifysrc' to be non NULL.
*/
void
isc_result_t
dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
/*%<
* Set the source address to be used with IPv6 NOTIFY messages.
@@ -931,17 +941,19 @@ dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc);
* Require:
*\li 'zone' to be a valid zone.
*\li 'notifysrc' to contain the address.
*
* Returns:
*\li #ISC_R_SUCCESS
*/
void
dns_zone_getnotifysrc6(dns_zone_t *zone, isc_sockaddr_t *notifysrc);
isc_sockaddr_t *
dns_zone_getnotifysrc6(dns_zone_t *zone);
/*%<
* Returns the source address set by a previous dns_zone_setnotifysrc6
* call, or the default of in6addr_any, port 0.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'notifysrc' to be non NULL.
*/
void
@@ -1516,8 +1528,8 @@ dns_zone_getsigresigninginterval(dns_zone_t *zone);
* \li 'zone' to be a valid zone.
*/
void
dns_zone_getsourceaddr(dns_zone_t *zone, isc_sockaddr_t *sourceaddr);
isc_sockaddr_t
dns_zone_getsourceaddr(dns_zone_t *zone);
/*%<
* Get the zone's source address from which it has last contacted the current
* primary server.
@@ -1525,18 +1537,17 @@ dns_zone_getsourceaddr(dns_zone_t *zone, isc_sockaddr_t *sourceaddr);
* Requires:
* \li 'zone' to be a valid zone.
* \li 'zone' has a non-empty primaries list.
* \li 'sourceaddr' to be non-NULL.
*/
isc_result_t
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *primaryaddr);
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *dest);
/*%<
* Get the zone's current primary server into '*primaryaddr'.
* Get the zone's current primary server into '*dest'.
*
* Requires:
* \li 'zone' to be a valid zone.
* \li 'zone' has a non-empty primaries list.
* \li 'primaryaddr' to be non-NULL.
* \li 'dest' != NULL.
*
* Returns:
*\li #ISC_R_SUCCESS if the current primary server was found
+29
View 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.
*/
#pragma once
/*! \file dns/zonekey.h */
#include <stdbool.h>
#include <dns/types.h>
bool
dns_zonekey_iszonekey(dns_rdata_t *keyrdata);
/*%<
* Determines if the key record contained in the rdata is a zone key.
*
* Requires:
* 'keyrdata' is not NULL.
*/
+4
View File
@@ -460,6 +460,10 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory);
*/
isc_result_t
dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
dst_key_t **keyp);
isc_result_t
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
/*%<
+40 -71
View File
@@ -189,19 +189,13 @@ dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first) {
isc_stdtime_t zrrsig_present;
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
zrrsig_present = published + ttlsig +
dns_kasp_zonepropagationdelay(kasp);
dns_kasp_zonepropagationdelay(kasp) +
dns_kasp_publishsafety(kasp);
if (zrrsig_present > syncpublish) {
syncpublish = zrrsig_present;
}
}
dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncpublish);
uint32_t lifetime = 0;
ret = dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
if (ret == ISC_R_SUCCESS && lifetime > 0) {
dst_key_settime(key, DST_TIME_SYNCDELETE,
(syncpublish + lifetime));
}
}
/*
@@ -249,17 +243,6 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
pub = now;
}
/*
* To calculate phase out times ("Retired", "Removed", ...),
* the key lifetime is required.
*/
uint32_t klifetime = 0;
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
if (ret != ISC_R_SUCCESS) {
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
klifetime = lifetime;
}
/*
* Calculate prepublication time.
*/
@@ -289,16 +272,13 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp,
true);
syncpub2 = pub + ttlsig +
dns_kasp_publishsafety(kasp) +
dns_kasp_zonepropagationdelay(kasp);
}
syncpub = ISC_MAX(syncpub1, syncpub2);
dst_key_settime(key->key, DST_TIME_SYNCPUBLISH,
syncpub);
if (klifetime > 0) {
dst_key_settime(key->key, DST_TIME_SYNCDELETE,
(syncpub + klifetime));
}
}
}
@@ -311,6 +291,13 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
if (ret != ISC_R_SUCCESS) {
uint32_t klifetime = 0;
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
if (ret != ISC_R_SUCCESS) {
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
klifetime = lifetime;
}
if (klifetime == 0) {
/*
* No inactive time and no lifetime,
@@ -411,7 +398,7 @@ keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
/* Initialize lifetime. */
if (r != ISC_R_SUCCESS) {
dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
l = lifetime - 1;
return;
}
/* Skip keys that are still hidden or already retiring. */
if (g != OMNIPRESENT) {
@@ -433,7 +420,6 @@ keymgr_key_update_lifetime(dns_dnsseckey_t *key, dns_kasp_t *kasp,
} else {
dst_key_unsettime(key->key, DST_TIME_INACTIVE);
dst_key_unsettime(key->key, DST_TIME_DELETE);
dst_key_unsettime(key->key, DST_TIME_SYNCDELETE);
}
}
}
@@ -1300,7 +1286,6 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
isc_result_t ret;
isc_stdtime_t lastchange, dstime, nexttime = now;
dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
uint32_t dsstate;
/*
* No need to wait if we move things into an uncertain state.
@@ -1370,12 +1355,15 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
* records. This translates to:
*
* Dsgn + zone-propagation-delay + max-zone-ttl.
*
* We will also add the retire-safety interval.
*/
nexttime = lastchange + ttlsig +
dns_kasp_zonepropagationdelay(kasp);
dns_kasp_zonepropagationdelay(kasp) +
dns_kasp_retiresafety(kasp);
/*
* Only add the sign delay Dsgn and retire-safety if
* there is an actual predecessor or successor key.
* Only add the sign delay Dsgn if there is an actual
* predecessor or successor key.
*/
uint32_t tag;
ret = dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
@@ -1385,8 +1373,7 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
DST_NUM_SUCCESSOR, &tag);
}
if (ret == ISC_R_SUCCESS) {
nexttime += dns_kasp_signdelay(kasp) +
dns_kasp_retiresafety(kasp);
nexttime += dns_kasp_signdelay(kasp);
}
break;
default:
@@ -1412,36 +1399,35 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type,
* This translates to:
*
* parent-propagation-delay + parent-ds-ttl.
*
* We will also add the retire-safety interval.
*/
case OMNIPRESENT:
case HIDDEN:
/* Make sure DS has been seen in/withdrawn from the
* parent. */
dsstate = next_state == HIDDEN ? DST_TIME_DSDELETE
: DST_TIME_DSPUBLISH;
ret = dst_key_gettime(key->key, dsstate, &dstime);
/* Make sure DS has been seen in the parent. */
ret = dst_key_gettime(key->key, DST_TIME_DSPUBLISH,
&dstime);
if (ret != ISC_R_SUCCESS || dstime > now) {
/* Not yet, try again in an hour. */
nexttime = now + 3600;
} else {
nexttime =
dstime + dns_kasp_dsttl(kasp) +
dns_kasp_parentpropagationdelay(kasp);
/*
* Only add the retire-safety if there is an
* actual predecessor or successor key.
*/
uint32_t tag;
ret = dst_key_getnum(key->key,
DST_NUM_PREDECESSOR, &tag);
if (ret != ISC_R_SUCCESS) {
ret = dst_key_getnum(key->key,
DST_NUM_SUCCESSOR,
&tag);
}
if (ret == ISC_R_SUCCESS) {
nexttime += dns_kasp_retiresafety(kasp);
}
dns_kasp_parentpropagationdelay(kasp) +
dns_kasp_retiresafety(kasp);
}
break;
case HIDDEN:
/* Make sure DS has been withdrawn from the parent. */
ret = dst_key_gettime(key->key, DST_TIME_DSDELETE,
&dstime);
if (ret != ISC_R_SUCCESS || dstime > now) {
/* Not yet, try again in an hour. */
nexttime = now + 3600;
} else {
nexttime =
dstime + dns_kasp_dsttl(kasp) +
dns_kasp_parentpropagationdelay(kasp) +
dns_kasp_retiresafety(kasp);
}
break;
default:
@@ -1777,9 +1763,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
if (prepub == 0 || prepub > now) {
/* No need to start rollover now. */
if (*nexttime == 0 || prepub < *nexttime) {
if (prepub > 0) {
*nexttime = prepub;
}
*nexttime = prepub;
}
return ISC_R_SUCCESS;
}
@@ -2038,20 +2022,6 @@ keymgr_purge_keyfile(dst_key_t *key, int type) {
}
}
static bool
dst_key_doublematch(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
int matches = 0;
for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
{
if (dns_kasp_key_match(kkey, key)) {
matches++;
}
}
return matches > 1;
}
/*
* Examine 'keys' and match 'kasp' policy.
*
@@ -2191,7 +2161,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
* matches the kasp policy.
*/
if (!dst_key_is_unused(dkey->key) &&
!dst_key_doublematch(dkey, kasp) &&
(dst_key_goal(dkey->key) ==
OMNIPRESENT) &&
!keymgr_dep(dkey->key, keyring,
+5 -9
View File
@@ -530,13 +530,14 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
return result;
}
isc_result_t
bool
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
dns_name_t *foundname, bool *wantdnssecp) {
dns_name_t *foundname) {
isc_result_t result;
dns_qpread_t qpr;
dns_keynode_t *keynode = NULL;
void *pval = NULL;
bool secure = false;
/*
* Is 'name' at or beneath a trusted key?
@@ -544,7 +545,6 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
REQUIRE(VALID_KEYTABLE(keytable));
REQUIRE(dns_name_isabsolute(name));
REQUIRE(wantdnssecp != NULL);
dns_qpmulti_query(keytable->table, &qpr);
result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, &pval, NULL);
@@ -553,16 +553,12 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
if (foundname != NULL) {
dns_name_copy(&keynode->name, foundname);
}
*wantdnssecp = true;
result = ISC_R_SUCCESS;
} else if (result == ISC_R_NOTFOUND) {
*wantdnssecp = false;
result = ISC_R_SUCCESS;
secure = true;
}
dns_qpread_destroy(keytable->table, &qpr);
return result;
return secure;
}
static isc_result_t
+19 -25
View File
@@ -3105,7 +3105,7 @@ dns_message_checksig_async(dns_message_t *msg, dns_view_t *view,
isc_result_t
dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
isc_buffer_t msgb;
isc_buffer_t b, msgb;
REQUIRE(DNS_MESSAGE_VALID(msg));
@@ -3126,7 +3126,7 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
return dns_tsig_verify(&msgb, msg, NULL, NULL);
}
} else {
dns_rdata_t sigrdata = DNS_RDATA_INIT;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_sig_t sig;
dns_rdataset_t keyset;
isc_result_t result;
@@ -3134,7 +3134,7 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
result = dns_rdataset_first(msg->sig0);
INSIST(result == ISC_R_SUCCESS);
dns_rdataset_current(msg->sig0, &sigrdata);
dns_rdataset_current(msg->sig0, &rdata);
/*
* This can occur when the message is a dynamic update, since
@@ -3143,11 +3143,11 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
* looked for in the additional section, and the dynamic update
* meta-records are in the prerequisite and update sections.
*/
if (sigrdata.length == 0) {
if (rdata.length == 0) {
return ISC_R_UNEXPECTEDEND;
}
result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
result = dns_rdata_tostruct(&rdata, &sig, NULL);
if (result != ISC_R_SUCCESS) {
return result;
}
@@ -3191,32 +3191,26 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
message_checks < max_message_checks;
key_checks++, result = dns_rdataset_next(&keyset))
{
dns_rdata_t keyrdata = DNS_RDATA_INIT;
dns_rdata_key_t ks;
dst_key_t *key = NULL;
isc_region_t r;
dns_rdataset_current(&keyset, &keyrdata);
dns_rdata_tostruct(&keyrdata, &ks, NULL);
dns_rdata_reset(&rdata);
dns_rdataset_current(&keyset, &rdata);
isc_buffer_init(&b, rdata.data, rdata.length);
isc_buffer_add(&b, rdata.length);
if (sig.algorithm != ks.algorithm ||
(ks.protocol != DNS_KEYPROTO_DNSSEC &&
ks.protocol != DNS_KEYPROTO_ANY))
{
continue;
}
dns_rdata_toregion(&keyrdata, &r);
if (dst_region_computeid(&r) != sig.keyid) {
continue;
}
result = dns_dnssec_keyfromrdata(&sig.signer, &keyrdata,
view->mctx, &key);
result = dst_key_fromdns(&sig.signer, rdata.rdclass, &b,
view->mctx, &key);
if (result != ISC_R_SUCCESS) {
continue;
}
if (dst_key_alg(key) != sig.algorithm ||
dst_key_id(key) != sig.keyid ||
!(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
dst_key_proto(key) == DNS_KEYPROTO_ANY))
{
dst_key_free(&key);
continue;
}
result = dns_dnssec_verifymessage(&msgb, msg, key);
dst_key_free(&key);
if (result == ISC_R_SUCCESS) {
+7 -27
View File
@@ -50,12 +50,6 @@ atomic_getuint8(isc_buffer_t *b) {
return ret;
}
static isc_result_t
addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset);
static isc_result_t
copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
isc_result_t result;
@@ -107,25 +101,8 @@ copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
isc_result_t
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) {
return addoptout(message, cache, node, covers, now, minttl, maxttl,
false, false, addedrdataset);
}
isc_result_t
dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
dns_dbnode_t *node, dns_rdatatype_t covers,
isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
bool optout, dns_rdataset_t *addedrdataset) {
return addoptout(message, cache, node, covers, now, minttl, maxttl,
optout, true, addedrdataset);
}
static isc_result_t
addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset) {
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset) {
isc_result_t result;
isc_buffer_t buffer;
isc_region_t r;
@@ -143,14 +120,17 @@ addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
/*
* Convert the authority data from 'message' into a negative cache
* rdataset, and store it in 'cache' at 'node'.
*
* We assume that all data in the authority section has been
* validated by the caller.
*/
REQUIRE(message != NULL);
/*
* We assume that all data in the authority section has been
* validated by the caller.
* If 'secure' is false, ignore 'optout'.
*/
optout = optout && secure;
/*
* Initialize the list.
+1
View File
@@ -55,6 +55,7 @@
#include <dns/stats.h>
#include <dns/time.h>
#include <dns/view.h>
#include <dns/zonekey.h>
#include "db_p.h"
#include "qpcache_p.h"
+16 -7
View File
@@ -43,7 +43,6 @@
#include <dns/callbacks.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/dnssec.h>
#include <dns/fixedname.h>
#include <dns/masterdump.h>
#include <dns/name.h>
@@ -59,6 +58,7 @@
#include <dns/time.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonekey.h>
#include "db_p.h"
#include "qpzone_p.h"
@@ -1143,17 +1143,25 @@ setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) {
bool hasnsec = false;
isc_result_t result;
version->secure = false;
version->havensec3 = false;
dns_rdataset_init(&keyset);
result = dns_db_findrdataset(db, origin, (dns_dbversion_t *)version,
dns_rdatatype_dnskey, 0, 0, &keyset, NULL);
if (result == ISC_R_SUCCESS) {
haszonekey = dns_dnssec_haszonekey(&keyset);
result = dns_rdataset_first(&keyset);
while (result == ISC_R_SUCCESS) {
dns_rdata_t keyrdata = DNS_RDATA_INIT;
dns_rdataset_current(&keyset, &keyrdata);
if (dns_zonekey_iszonekey(&keyrdata)) {
haszonekey = true;
break;
}
result = dns_rdataset_next(&keyset);
}
dns_rdataset_disassociate(&keyset);
}
if (!haszonekey) {
version->secure = false;
version->havensec3 = false;
return;
}
@@ -1173,11 +1181,12 @@ setsecure(dns_db_t *db, qpz_version_t *version, dns_dbnode_t *origin) {
setnsec3parameters(db, version);
/*
* If we don't have a valid NSEC/NSEC3 chain,
* clear the secure flag.
* Do we have a valid NSEC/NSEC3 chain?
*/
if (version->havensec3 || hasnsec) {
version->secure = true;
} else {
version->secure = false;
}
}
+985 -1267
View File
File diff suppressed because it is too large Load Diff
+52 -52
View File
@@ -1011,46 +1011,59 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
static isc_result_t
select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) {
isc_result_t result;
dns_rdata_rrsig_t *siginfo = val->siginfo;
isc_buffer_t b;
dns_rdata_t rdata = DNS_RDATA_INIT;
dst_key_t *oldkey = val->key;
bool no_rdata = false;
if (val->key == NULL) {
if (oldkey == NULL) {
result = dns_rdataset_first(rdataset);
} else {
dst_key_free(&val->key);
dst_key_free(&oldkey);
val->key = NULL;
result = dns_rdataset_next(rdataset);
}
if (result == ISC_R_NOMORE) {
return ISC_R_NOTFOUND;
if (result != ISC_R_SUCCESS) {
goto done;
}
for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) {
dns_rdata_rrsig_t *siginfo = val->siginfo;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_dnskey_t key;
isc_region_t r;
do {
dns_rdataset_current(rdataset, &rdata);
dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
if (key.algorithm != siginfo->algorithm ||
(key.flags & DNS_KEYFLAG_REVOKE) != 0 ||
!dns_dnssec_iszonekey(&key))
{
continue;
}
dns_rdata_toregion(&rdata, &r);
if (dst_region_computeid(&r) != siginfo->keyid) {
continue;
}
result = dns_dnssec_keyfromrdata(&siginfo->signer, &rdata,
val->view->mctx, &val->key);
isc_buffer_init(&b, rdata.data, rdata.length);
isc_buffer_add(&b, rdata.length);
INSIST(val->key == NULL);
result = dst_key_fromdns_ex(&siginfo->signer, rdata.rdclass, &b,
val->view->mctx, no_rdata,
&val->key);
if (result == ISC_R_SUCCESS) {
/* found the key we wanted */
break;
if (siginfo->algorithm ==
(dns_secalg_t)dst_key_alg(val->key) &&
siginfo->keyid ==
(dns_keytag_t)dst_key_id(val->key) &&
(dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) ==
0 &&
dst_key_iszonekey(val->key))
{
if (no_rdata) {
/* Retry with full key */
dns_rdata_reset(&rdata);
dst_key_free(&val->key);
no_rdata = false;
continue;
}
/* This is the key we're looking for. */
goto done;
}
dst_key_free(&val->key);
}
}
dns_rdata_reset(&rdata);
result = dns_rdataset_next(rdataset);
no_rdata = true;
} while (result == ISC_R_SUCCESS);
done:
if (result == ISC_R_NOMORE) {
result = ISC_R_NOTFOUND;
}
@@ -1232,10 +1245,7 @@ compute_keytag(dns_rdata_t *rdata) {
static bool
over_max_validations(dns_validator_t *val) {
if (val->nvalidations == NULL ||
isc_counter_used(val->nvalidations) <
isc_counter_getlimit(val->nvalidations))
{
if (val->nvalidations == NULL || (*val->nvalidations) > 0) {
return false;
}
@@ -1249,14 +1259,14 @@ consume_validation(dns_validator_t *val) {
if (val->nvalidations == NULL) {
return;
}
(void)isc_counter_increment(val->nvalidations);
INSIST((*val->nvalidations) > 0);
(*val->nvalidations)--;
}
static bool
over_max_fails(dns_validator_t *val) {
if (val->nfails == NULL ||
isc_counter_used(val->nfails) < isc_counter_getlimit(val->nfails))
{
if (val->nfails == NULL || (*val->nfails) > 0) {
return false;
}
@@ -1270,7 +1280,9 @@ consume_validation_fail(dns_validator_t *val) {
if (val->nfails == NULL) {
return;
}
(void)isc_counter_increment(val->nfails);
INSIST((*val->nfails) > 0);
(*val->nfails)--;
}
/*%
@@ -3380,7 +3392,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
isc_loop_t *loop, isc_job_cb cb, void *arg,
isc_counter_t *nvalidations, isc_counter_t *nfails,
uint32_t *nvalidations, uint32_t *nfails,
isc_counter_t *qc, isc_counter_t *gqc,
dns_edectx_t *edectx, dns_validator_t **validatorp) {
isc_result_t result = ISC_R_FAILURE;
@@ -3412,6 +3424,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
.cb = cb,
.arg = arg,
.rdata = DNS_RDATA_INIT,
.nvalidations = nvalidations,
.nfails = nfails,
.edectx = edectx,
};
@@ -3421,14 +3435,6 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_message_attach(message, &val->message);
}
if (nfails != NULL) {
isc_counter_attach(nfails, &val->nfails);
}
if (nvalidations != NULL) {
isc_counter_attach(nvalidations, &val->nvalidations);
}
if (qc != NULL) {
isc_counter_attach(qc, &val->qc);
}
@@ -3521,12 +3527,6 @@ destroy_validator(dns_validator_t *val) {
if (val->message != NULL) {
dns_message_detach(&val->message);
}
if (val->nfails != NULL) {
isc_counter_detach(&val->nfails);
}
if (val->nvalidations != NULL) {
isc_counter_detach(&val->nvalidations);
}
if (val->qc != NULL) {
isc_counter_detach(&val->qc);
}
+7 -17
View File
@@ -1533,41 +1533,31 @@ dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now, const dns_name_t *name,
return dns_ntatable_covered(view->ntatable_priv, now, name, anchor);
}
isc_result_t
bool
dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
isc_stdtime_t now, bool checknta, bool *ntap,
bool *secure_domain) {
isc_result_t result;
isc_stdtime_t now, bool checknta, bool *ntap) {
bool secure = false;
dns_fixedname_t fn;
dns_name_t *anchor;
REQUIRE(DNS_VIEW_VALID(view));
if (view->secroots_priv == NULL) {
return ISC_R_NOTFOUND;
if (!view->enablevalidation || view->secroots_priv == NULL) {
return false;
}
anchor = dns_fixedname_initname(&fn);
result = dns_keytable_issecuredomain(view->secroots_priv, name, anchor,
&secure);
if (result != ISC_R_SUCCESS) {
return result;
}
secure = dns_keytable_issecuredomain(view->secroots_priv, name, anchor);
SET_IF_NOT_NULL(ntap, false);
if (checknta && secure && view->ntatable_priv != NULL &&
dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
{
if (ntap != NULL) {
*ntap = true;
}
SET_IF_NOT_NULL(ntap, true);
secure = false;
}
*secure_domain = secure;
return ISC_R_SUCCESS;
return secure;
}
void
+46 -60
View File
@@ -5998,123 +5998,106 @@ dns_zone_getkeyopts(dns_zone_t *zone) {
return atomic_load_relaxed(&zone->keyopts);
}
void
isc_result_t
dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(xfrsource != NULL);
LOCK_ZONE(zone);
zone->xfrsource4 = *xfrsource;
UNLOCK_ZONE(zone);
return ISC_R_SUCCESS;
}
void
dns_zone_getxfrsource4(dns_zone_t *zone, isc_sockaddr_t *xfrsource) {
isc_sockaddr_t *
dns_zone_getxfrsource4(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(xfrsource != NULL);
LOCK_ZONE(zone);
*xfrsource = zone->xfrsource4;
UNLOCK_ZONE(zone);
return &zone->xfrsource4;
}
void
isc_result_t
dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(xfrsource != NULL);
LOCK_ZONE(zone);
zone->xfrsource6 = *xfrsource;
UNLOCK_ZONE(zone);
return ISC_R_SUCCESS;
}
void
dns_zone_getxfrsource6(dns_zone_t *zone, isc_sockaddr_t *xfrsource) {
isc_sockaddr_t *
dns_zone_getxfrsource6(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(xfrsource != NULL);
LOCK_ZONE(zone);
*xfrsource = zone->xfrsource6;
UNLOCK_ZONE(zone);
return &zone->xfrsource6;
}
void
isc_result_t
dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(parentalsrc != NULL);
LOCK_ZONE(zone);
zone->parentalsrc4 = *parentalsrc;
UNLOCK_ZONE(zone);
return ISC_R_SUCCESS;
}
void
dns_zone_getparentalsrc4(dns_zone_t *zone, isc_sockaddr_t *parentalsrc) {
isc_sockaddr_t *
dns_zone_getparentalsrc4(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(parentalsrc != NULL);
LOCK_ZONE(zone);
*parentalsrc = zone->parentalsrc4;
UNLOCK_ZONE(zone);
return &zone->parentalsrc4;
}
void
isc_result_t
dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc) {
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
zone->parentalsrc6 = *parentalsrc;
UNLOCK_ZONE(zone);
return ISC_R_SUCCESS;
}
void
dns_zone_getparentalsrc6(dns_zone_t *zone, isc_sockaddr_t *parentalsrc) {
isc_sockaddr_t *
dns_zone_getparentalsrc6(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(parentalsrc != NULL);
LOCK_ZONE(zone);
*parentalsrc = zone->parentalsrc6;
UNLOCK_ZONE(zone);
return &zone->parentalsrc6;
}
void
isc_result_t
dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(notifysrc != NULL);
LOCK_ZONE(zone);
zone->notifysrc4 = *notifysrc;
UNLOCK_ZONE(zone);
return ISC_R_SUCCESS;
}
void
dns_zone_getnotifysrc4(dns_zone_t *zone, isc_sockaddr_t *notifysrc) {
isc_sockaddr_t *
dns_zone_getnotifysrc4(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(notifysrc != NULL);
LOCK_ZONE(zone);
*notifysrc = zone->notifysrc4;
UNLOCK_ZONE(zone);
return &zone->notifysrc4;
}
void
isc_result_t
dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(notifysrc != NULL);
LOCK_ZONE(zone);
zone->notifysrc6 = *notifysrc;
UNLOCK_ZONE(zone);
return ISC_R_SUCCESS;
}
void
dns_zone_getnotifysrc6(dns_zone_t *zone, isc_sockaddr_t *notifysrc) {
isc_sockaddr_t *
dns_zone_getnotifysrc6(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(notifysrc != NULL);
LOCK_ZONE(zone);
*notifysrc = zone->notifysrc6;
UNLOCK_ZONE(zone);
return &zone->notifysrc6;
}
void
@@ -18388,28 +18371,31 @@ dns_zone_getsigresigninginterval(dns_zone_t *zone) {
return zone->sigresigninginterval;
}
void
dns_zone_getsourceaddr(dns_zone_t *zone, isc_sockaddr_t *sourceaddr) {
isc_sockaddr_t
dns_zone_getsourceaddr(dns_zone_t *zone) {
isc_sockaddr_t sourceaddr;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(sourceaddr != NULL);
LOCK_ZONE(zone);
INSIST(dns_remote_count(&zone->primaries) > 0);
*sourceaddr = zone->sourceaddr;
sourceaddr = zone->sourceaddr;
UNLOCK_ZONE(zone);
return sourceaddr;
}
isc_result_t
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *primaryaddr) {
dns_zone_getprimaryaddr(dns_zone_t *zone, isc_sockaddr_t *dest) {
isc_result_t result = ISC_R_NOMORE;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(primaryaddr != NULL);
REQUIRE(dest != NULL);
LOCK_ZONE(zone);
INSIST(dns_remote_count(&zone->primaries) > 0);
if (!dns_remote_done(&zone->primaries)) {
*primaryaddr = dns_remote_curraddr(&zone->primaries);
*dest = dns_remote_curraddr(&zone->primaries);
result = ISC_R_SUCCESS;
}
UNLOCK_ZONE(zone);
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <stdbool.h>
#include <isc/result.h>
#include <isc/types.h>
#include <isc/util.h>
#include <dns/keyvalues.h>
#include <dns/rdata.h>
#include <dns/rdatastruct.h>
#include <dns/types.h>
#include <dns/zonekey.h>
bool
dns_zonekey_iszonekey(dns_rdata_t *keyrdata) {
isc_result_t result;
dns_rdata_dnskey_t key;
bool iszonekey = true;
REQUIRE(keyrdata != NULL);
result = dns_rdata_tostruct(keyrdata, &key, NULL);
if (result != ISC_R_SUCCESS) {
return false;
}
if ((key.flags & DNS_KEYTYPE_NOAUTH) != 0) {
iszonekey = false;
}
if ((key.flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE) {
iszonekey = false;
}
if (key.protocol != DNS_KEYPROTO_DNSSEC &&
key.protocol != DNS_KEYPROTO_ANY)
{
iszonekey = false;
}
return iszonekey;
}
-1
View File
@@ -26,7 +26,6 @@ libisc_la_HEADERS = \
include/isc/file.h \
include/isc/formatcheck.h \
include/isc/fuzz.h \
include/isc/fxhash.h \
include/isc/getaddresses.h \
include/isc/hash.h \
include/isc/hashmap.h \
+9 -19
View File
@@ -131,28 +131,18 @@ isc__ascii_load8(const uint8_t *ptr) {
* Compare `len` bytes at `a` and `b` for case-insensitive equality
*/
static inline bool
isc_ascii_lowerequal(const uint8_t *restrict a, const uint8_t *restrict b,
unsigned int len) {
isc_ascii_lowerequal(const uint8_t *a, const uint8_t *b, unsigned int len) {
uint64_t a8 = 0, b8 = 0;
if (len >= 8) {
const uint8_t *a_tail = a + len - 8;
const uint8_t *b_tail = b + len - 8;
while (len >= 8) {
a8 = isc_ascii_tolower8(isc__ascii_load8(a));
b8 = isc_ascii_tolower8(isc__ascii_load8(b));
if (a8 != b8) {
return false;
}
len -= 8;
a += 8;
b += 8;
while (len >= 8) {
a8 = isc_ascii_tolower8(isc__ascii_load8(a));
b8 = isc_ascii_tolower8(isc__ascii_load8(b));
if (a8 != b8) {
return false;
}
a8 = isc_ascii_tolower8(isc__ascii_load8(a_tail));
b8 = isc_ascii_tolower8(isc__ascii_load8(b_tail));
return a8 == b8;
len -= 8;
a += 8;
b += 8;
}
while (len-- > 0) {
if (isc_ascii_tolower(*a++) != isc_ascii_tolower(*b++)) {
return false;
-89
View File
@@ -1,89 +0,0 @@
#pragma once
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/* The constant K from Rust's fxhash */
#define K 0x9e3779b97f4a7c15ull
static inline size_t
rotate_left(size_t x, unsigned int n) {
return (x << n) | (x >> (sizeof(size_t) * 8 - n));
}
static inline size_t
fx_add_to_hash(size_t hash, size_t i) {
return rotate_left(hash, 5) ^ i * K;
}
/*
* Beware: this implementation will use an approximate conversion to lowercase.
* This is ok as fxhash is already not hash-flooding resistant and we use it
* only for config parsing.
*/
static inline size_t
fx_hash_bytes(size_t initial_hash, const uint8_t *restrict bytes, size_t len,
bool case_sensitive) {
size_t hash = initial_hash;
size_t case_mask = case_sensitive
? -1ull
: (0b11011111 * 0x0101010101010101ull);
while (len >= sizeof(size_t)) {
size_t value;
memmove(&value, bytes, sizeof(size_t));
hash = fx_add_to_hash(hash, value & case_mask);
bytes += sizeof(size_t);
len -= sizeof(size_t);
}
/* Will be ignored if sizeof(size_t) <= 4 */
if (len >= 4) {
uint32_t value;
memmove(&value, bytes, sizeof(uint32_t));
hash = fx_add_to_hash(hash, value & case_mask);
bytes += 4;
len -= 4;
}
/* Will be ignored if sizeof(size_t) <= 2 */
if (len >= 2) {
uint16_t value;
memmove(&value, bytes, sizeof(uint16_t));
hash = fx_add_to_hash(hash, value & case_mask);
bytes += 2;
len -= 2;
}
if (len >= 1) {
hash = fx_add_to_hash(hash, bytes[0] & case_mask);
}
return hash;
}
+11 -9
View File
@@ -16,7 +16,6 @@
#include <stdbool.h>
#include <isc/ascii.h>
#include <isc/fxhash.h>
#include <isc/hash.h>
#include <isc/hashmap.h>
#include <isc/magic.h>
@@ -32,9 +31,9 @@ typedef struct elt {
isc_symvalue_t value;
} elt_t;
/* 4 bits means 16 entries at creation, which matches the common use of
/* 7 bits means 128 entries at creation, which matches the common use of
* symtab */
#define ISC_SYMTAB_INIT_HASH_BITS 4
#define ISC_SYMTAB_INIT_HASH_BITS 7
#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
@@ -123,7 +122,7 @@ elt__match(void *node, const void *key0, bool case_sensitive) {
if (case_sensitive) {
return memcmp(elt->key, key->key, key->size) == 0;
} else {
return isc_ascii_lowerequal(elt->key, key->key, key->size);
return isc_ascii_lowercmp(elt->key, key->key, key->size) == 0;
}
}
@@ -137,11 +136,14 @@ elt_match_nocase(void *node, const void *key) {
return elt__match(node, key, false);
}
static inline uint32_t
elt_hash(elt_t *restrict elt, bool case_sensitive) {
const uint8_t *ptr = elt->key;
size_t len = elt->size;
return fx_hash_bytes(0, ptr, len, case_sensitive);
static uint32_t
elt_hash(elt_t *elt, bool case_sensitive) {
isc_hash32_t hash;
isc_hash32_init(&hash);
isc_hash32_hash(&hash, elt->key, elt->size, case_sensitive);
isc_hash32_hash(&hash, &elt->type, sizeof(elt->type), false);
return isc_hash32_finalize(&hash);
}
isc_result_t
+1 -13
View File
@@ -1290,7 +1290,6 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
isc_stdtime_t now;
uint32_t when;
isc_buffer_t db;
bool alwaysvalid;
/*
* If we have already seen a cookie option skip this cookie option.
@@ -1336,22 +1335,11 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
when = isc_buffer_getuint32(buf);
isc_buffer_forward(buf, 8);
/*
* For '-T cookiealwaysvalid' still process everything to not skew any
* performance tests involving cookies, but make sure that the cookie
* check passes in the end, given the cookie was structurally correct.
*/
alwaysvalid = ns_server_getoption(client->manager->sctx,
NS_SERVER_COOKIEALWAYSVALID);
/*
* Allow for a 5 minute clock skew between servers sharing a secret.
* Only accept COOKIE if we have talked to the client in the last hour.
*/
now = isc_stdtime_now();
if (alwaysvalid) {
now = when;
}
if (isc_serial_gt(when, (now + 300)) /* In the future. */ ||
isc_serial_lt(when, (now - 3600)) /* In the past. */)
{
@@ -1364,7 +1352,7 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
isc_buffer_init(&db, dbuf, sizeof(dbuf));
compute_cookie(client, when, client->manager->sctx->secret, &db);
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE) || alwaysvalid) {
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE)) {
ns_stats_increment(client->manager->sctx->nsstats,
ns_statscounter_cookiematch);
client->attributes |= NS_CLIENTATTR_HAVECOOKIE;
+18 -19
View File
@@ -32,25 +32,24 @@
#include <ns/types.h>
#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */
#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */
#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */
#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */
#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */
#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */
#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */
#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */
#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */
#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */
#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */
#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */
#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */
#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */
#define NS_SERVER_TRANSFERINSECS 0x00008000U /*%< -T transferinsecs */
#define NS_SERVER_TRANSFERSLOWLY 0x00010000U /*%< -T transferslowly */
#define NS_SERVER_TRANSFERSTUCK 0x00020000U /*%< -T transferstuck */
#define NS_SERVER_LOGRESPONSES 0x00040000U /*%< log responses */
#define NS_SERVER_COOKIEALWAYSVALID 0x00080000U /*%< -T cookiealwaysvalid */
#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */
#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */
#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */
#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */
#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */
#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */
#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */
#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */
#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */
#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */
#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */
#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */
#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */
#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */
#define NS_SERVER_TRANSFERINSECS 0x00008000U /*%< -T transferinsecs */
#define NS_SERVER_TRANSFERSLOWLY 0x00010000U /*%< -T transferslowly */
#define NS_SERVER_TRANSFERSTUCK 0x00020000U /*%< -T transferstuck */
#define NS_SERVER_LOGRESPONSES 0x00040000U /*%< log responses */
/*%
* Type for callback function to get hostname.
+11 -19
View File
@@ -2420,33 +2420,25 @@ get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(keyrdataset))
{
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_dnskey_t key;
isc_region_t r;
isc_buffer_t b;
dns_rdataset_current(keyrdataset, &rdata);
dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
if (rrsig->algorithm != key.algorithm ||
!dns_dnssec_iszonekey(&key))
isc_buffer_init(&b, rdata.data, rdata.length);
isc_buffer_add(&b, rdata.length);
result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
client->manager->mctx, keyp);
if (result != ISC_R_SUCCESS) {
continue;
}
if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
dst_key_iszonekey(*keyp))
{
continue;
}
dns_rdata_toregion(&rdata, &r);
if (dst_region_computeid(&r) != rrsig->keyid) {
continue;
}
result = dns_dnssec_keyfromrdata(&rrsig->signer, &rdata,
client->manager->mctx, keyp);
if (result == ISC_R_SUCCESS) {
secure = true;
break;
}
dst_key_free(keyp);
}
return secure;
}
+19 -39
View File
@@ -535,7 +535,6 @@ ISC_LOOP_TEST_IMPL(find) {
/* check issecuredomain() */
ISC_LOOP_TEST_IMPL(issecuredomain) {
bool issecure;
const char **n;
const char *names[] = { "example.com", "sub.example.com",
"null.example", "sub.null.example", NULL };
@@ -550,22 +549,16 @@ ISC_LOOP_TEST_IMPL(issecuredomain) {
* of installing a null key).
*/
for (n = names; *n != NULL; n++) {
assert_int_equal(dns_keytable_issecuredomain(keytable,
str2name(*n), NULL,
&issecure),
ISC_R_SUCCESS);
assert_true(issecure);
assert_true(dns_keytable_issecuredomain(keytable, str2name(*n),
NULL));
}
/*
* If the key table has no entry (not even a null one) for a domain or
* any of its ancestors, that domain is considered insecure.
*/
assert_int_equal(dns_keytable_issecuredomain(keytable,
str2name("example.org"),
NULL, &issecure),
ISC_R_SUCCESS);
assert_false(issecure);
assert_false(dns_keytable_issecuredomain(
keytable, str2name("example.org"), NULL));
destroy_tables();
@@ -595,7 +588,7 @@ ISC_LOOP_TEST_IMPL(dump) {
/* check negative trust anchors */
ISC_LOOP_TEST_IMPL(nta) {
isc_result_t result;
bool issecure, covered;
bool covered;
dns_fixedname_t fn;
dns_name_t *keyname = dns_fixedname_name(&fn);
unsigned char digest[ISC_MAX_MD_SIZE];
@@ -626,20 +619,15 @@ ISC_LOOP_TEST_IMPL(nta) {
assert_int_equal(result, ISC_R_SUCCESS);
/* Should be secure */
result = dns_view_issecuredomain(myview,
str2name("test.secure.example"), now,
true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(
myview, str2name("test.secure.example"), now, true, &covered));
assert_false(covered);
assert_true(issecure);
/* Should not be secure */
result = dns_view_issecuredomain(myview,
str2name("test.insecure.example"), now,
true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_false(dns_view_issecuredomain(myview,
str2name("test.insecure.example"),
now, true, &covered));
assert_true(covered);
assert_false(issecure);
/* NTA covered */
covered = dns_view_ntacovers(myview, now, str2name("insecure.example"),
@@ -652,38 +640,30 @@ ISC_LOOP_TEST_IMPL(nta) {
assert_false(covered);
/* As of now + 2, the NTA should be clear */
result = dns_view_issecuredomain(myview,
str2name("test.insecure.example"),
now + 2, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(myview,
str2name("test.insecure.example"),
now + 2, true, &covered));
assert_false(covered);
assert_true(issecure);
/* Now check deletion */
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
now, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(
myview, str2name("test.new.example"), now, true, &covered));
assert_false(covered);
assert_true(issecure);
result = dns_ntatable_add(ntatable, str2name("new.example"), false, now,
3600);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
now, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_false(dns_view_issecuredomain(
myview, str2name("test.new.example"), now, true, &covered));
assert_true(covered);
assert_false(issecure);
result = dns_ntatable_delete(ntatable, str2name("new.example"));
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
now, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(
myview, str2name("test.new.example"), now, true, &covered));
assert_false(covered);
assert_true(issecure);
isc_loopmgr_shutdown(loopmgr);