mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-26 11:22:52 -04:00
new: usr: Add support for Extended DNS Error 24 (Invalid Data)
Extended DNS Error 24 (Invalid Data) is returned when the server cannot answer data for a zone it is configured for. This occurs typically when an authoritative server does not have loaded the DB of a configured zone, or a secondary server zone is expired. See RFC 8914 section 4.25. See #1836 Merge branch 'colin/ede24' into 'main' See merge request isc-projects/bind9!11169
This commit is contained in:
commit
4941d33a8a
7 changed files with 198 additions and 2 deletions
21
bin/tests/system/ede24/ns1/foo.fr.db
Normal file
21
bin/tests/system/ede24/ns1/foo.fr.db
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; SPDX-License-Identifier: MPL-2.0
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
;
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
$TTL 1
|
||||
foo.fr. IN SOA ns.foo.fr. op.foo.fr. (
|
||||
3 ; serial
|
||||
1 ; refresh
|
||||
1 ; retry
|
||||
1 ; expire
|
||||
60 ; minimum
|
||||
)
|
||||
foo.fr. NS ns.foo.fr.
|
||||
ns.foo.fr. A 10.53.0.1
|
||||
36
bin/tests/system/ede24/ns1/named.conf.j2
Normal file
36
bin/tests/system/ede24/ns1/named.conf.j2
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
listen-on port @PORT@ { 10.53.0.1; };
|
||||
transfer-source 10.53.0.1;
|
||||
pid-file "named.pid";
|
||||
recursion no;
|
||||
also-notify { 10.53.0.2 port @PORT@; };
|
||||
notify-source 10.53.0.1;
|
||||
};
|
||||
|
||||
zone "foo.fr" {
|
||||
type primary;
|
||||
allow-transfer{ 10.53.0.2; };
|
||||
file "foo.fr.db";
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
35
bin/tests/system/ede24/ns2/named.conf.j2
Normal file
35
bin/tests/system/ede24/ns2/named.conf.j2
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
listen-on port @PORT@ { 10.53.0.2; };
|
||||
transfer-source 10.53.0.2;
|
||||
pid-file "named.pid";
|
||||
recursion no;
|
||||
};
|
||||
|
||||
zone "foo.fr" {
|
||||
min-refresh-time 1;
|
||||
min-retry-time 1;
|
||||
type secondary;
|
||||
primaries { 10.53.0.1 port @PORT@; };
|
||||
};
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm @DEFAULT_HMAC@;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
71
bin/tests/system/ede24/tests_ede24.py
Normal file
71
bin/tests/system/ede24/tests_ede24.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import os
|
||||
|
||||
import isctest
|
||||
|
||||
|
||||
def check_soa_noerror():
|
||||
msg = isctest.query.create("foo.fr", "SOA")
|
||||
res = isctest.query.udp(msg, "10.53.0.2")
|
||||
isctest.check.noerror(res)
|
||||
|
||||
|
||||
def check_soa_servfail_ede24(edemsg):
|
||||
msg = isctest.query.create("foo.fr", "SOA")
|
||||
res = isctest.query.udp(msg, "10.53.0.2")
|
||||
isctest.check.servfail(res)
|
||||
|
||||
# Few CI machines uses old version of dnspython which doesn't supports
|
||||
# EDNS, so we effectively bypass the check for those one. (It's fine, a
|
||||
# bunch of other CI machines _does_ have recent version of dnspython).
|
||||
if hasattr(res, "extended_errors"):
|
||||
assert len(res.extended_errors()) == 1
|
||||
assert res.extended_errors()[0].to_text() == f"EDE 24 (Invalid Data): {edemsg}"
|
||||
|
||||
|
||||
def test_ede24_noloaded(ns1, ns2):
|
||||
# Sanity check that everything works first
|
||||
check_soa_noerror()
|
||||
|
||||
# Stop all servers, and we'll restart only ns2.
|
||||
ns1.stop()
|
||||
ns2.stop()
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
ns2.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
|
||||
watcher.wait_for_line("failure trying primary 10.53.0.1")
|
||||
|
||||
# ns2 attempts an XFR but ns1 since is off the zone DB can't be loaded.
|
||||
check_soa_servfail_ede24("zone not loaded")
|
||||
|
||||
|
||||
def test_ede24_expired(ns1, ns2):
|
||||
# Restart ns1 then checks the server notify the zone in ns2 and ns2 serves
|
||||
# the zone again.
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
ns1.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
|
||||
watcher.wait_for_line("Transfer status: success")
|
||||
check_soa_noerror()
|
||||
|
||||
# Stop the primary and wait for expiration of the zone in the secondary.
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
ns1.stop()
|
||||
watcher.wait_for_line(" zone foo.fr/IN: expired")
|
||||
|
||||
# ns2 can't answer anymore.
|
||||
check_soa_servfail_ede24("zone expired")
|
||||
|
||||
# Restart the primary and wait for the zone to be back up again.
|
||||
with ns2.watch_log_from_here() as watcher:
|
||||
ns1.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
|
||||
watcher.wait_for_line("Transfer status: success")
|
||||
check_soa_noerror()
|
||||
|
|
@ -2792,6 +2792,15 @@ dns_zone_getcfg(dns_zone_t *zone);
|
|||
* \li 'zone' to be a valid zone.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_zone_isexpired(dns_zone_t *zone);
|
||||
/*%<
|
||||
* Return true if a (secondary, mirror, etc.) zone is expired
|
||||
*
|
||||
* Requires:
|
||||
* \li 'zone\ to be a valid zone.
|
||||
*/
|
||||
|
||||
#if DNS_ZONE_TRACE
|
||||
#define dns_zone_ref(ptr) dns_zone__ref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_zone_unref(ptr) dns_zone__unref(ptr, __func__, __FILE__, __LINE__)
|
||||
|
|
|
|||
|
|
@ -11848,13 +11848,13 @@ zone_expire(dns_zone_t *zone) {
|
|||
|
||||
REQUIRE(LOCKED_ZONE(zone));
|
||||
|
||||
dns_zone_log(zone, ISC_LOG_WARNING, "expired");
|
||||
|
||||
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXPIRED);
|
||||
zone->refresh = DNS_ZONE_DEFAULTREFRESH;
|
||||
zone->retry = DNS_ZONE_DEFAULTRETRY;
|
||||
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
|
||||
|
||||
dns_zone_log(zone, ISC_LOG_WARNING, "expired");
|
||||
|
||||
/*
|
||||
* An RPZ zone has expired; before unloading it, we must
|
||||
* first remove it from the RPZ summary database. The
|
||||
|
|
@ -17617,6 +17617,7 @@ again:
|
|||
isc_time_compare(&expiretime, &zone->expiretime) > 0)
|
||||
{
|
||||
zone->expiretime = expiretime;
|
||||
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_EXPIRED);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -24249,3 +24250,10 @@ dns_zone_getcfg(dns_zone_t *zone) {
|
|||
|
||||
return zone->cfg;
|
||||
}
|
||||
|
||||
bool
|
||||
dns_zone_isexpired(dns_zone_t *zone) {
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
|
||||
return DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXPIRED);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1250,6 +1250,11 @@ query_getzonedb(ns_client_t *client, const dns_name_t *name,
|
|||
partial = true;
|
||||
}
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
if (dns_zone_isexpired(zone)) {
|
||||
result = DNS_R_EXPIRED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = dns_zone_getdb(zone, &db);
|
||||
}
|
||||
|
||||
|
|
@ -5630,8 +5635,19 @@ ns__query_start(query_ctx_t *qctx) {
|
|||
QUERY_ERROR(qctx, DNS_R_REFUSED);
|
||||
}
|
||||
} else {
|
||||
const char *edemsg = NULL;
|
||||
|
||||
CCTRACE(ISC_LOG_ERROR, "ns__query_start: query_getdb "
|
||||
"failed");
|
||||
|
||||
if (result == DNS_R_NOTLOADED) {
|
||||
edemsg = "zone not loaded";
|
||||
} else if (result == DNS_R_EXPIRED) {
|
||||
edemsg = "zone expired";
|
||||
}
|
||||
dns_ede_add(&qctx->client->edectx, DNS_EDE_INVALIDDATA,
|
||||
edemsg);
|
||||
|
||||
QUERY_ERROR(qctx, result);
|
||||
}
|
||||
return ns_query_done(qctx);
|
||||
|
|
|
|||
Loading…
Reference in a new issue