Merge branch '3410-rpz-extended-errors' into 'main'

RPZ Extended DNS Error Codes

Closes #3410

See merge request isc-projects/bind9!6700
This commit is contained in:
Arаm Sаrgsyаn 2022-08-31 09:21:11 +00:00
commit 692975746f
16 changed files with 235 additions and 9 deletions

View file

@ -1,3 +1,6 @@
5950. [func] Implement a feature to set an Extended DNS Error (EDE)
code on responses modified by RPZ. [GL #3410]
5949. [func] Add new isc_loopmgr API that runs the application
event loops and completely replaces the isc_app
API. Refactor the isc_taskmgr, isc_timermgr and

View file

@ -18,6 +18,7 @@
#include <limits.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -2395,6 +2396,18 @@ configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
*old_rpz_okp = false;
}
obj = cfg_tuple_get(rpz_obj, "ede");
if (!cfg_obj_isstring(obj)) {
zone->ede = 0;
} else {
str = cfg_obj_asstring(obj);
zone->ede = dns_rpz_str2ede(str);
INSIST(zone->ede != UINT16_MAX);
}
if (*old_rpz_okp && zone->ede != old->ede) {
*old_rpz_okp = false;
}
obj = cfg_tuple_get(rpz_obj, "add-soa");
if (cfg_obj_isvoid(obj)) {
zone->addsoa = add_soa_default;

View file

@ -0,0 +1,23 @@
/*
* 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.
*/
zone "example.com." {
type primary;
file "example.com.zone";
};
options {
response-policy {
zone "example.com." ede unsupported;
};
};

View file

@ -0,0 +1,23 @@
/*
* 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.
*/
zone "example.com." {
type primary;
file "example.com.zone";
};
options {
response-policy {
zone "example.com." ede none;
};
};

View file

@ -0,0 +1,23 @@
/*
* 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.
*/
zone "example.com." {
type primary;
file "example.com.zone";
};
options {
response-policy {
zone "example.com." ede filtered;
};
};

View file

@ -48,7 +48,7 @@ options {
zone "bl-drop" policy drop;
zone "bl-tcp-only" policy tcp-only;
zone "bl.tld2";
zone "manual-update-rpz";
zone "manual-update-rpz" ede forged;
zone "mixed-case-rpz";
}
add-soa yes

View file

@ -26,7 +26,7 @@ options {
dnssec-validation yes;
response-policy {
zone "policy2" add-soa no;
zone "policy2" add-soa no ede none;
} qname-wait-recurse no
nsip-enable yes
nsdname-enable yes

View file

@ -848,6 +848,11 @@ EOF
$PERL ../stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3
restart 3 "rebuild-bl-rpz"
t=`expr $t + 1`
echo_i "checking the configured extended DNS error code (EDE) (${t})"
$DIG -p ${PORT} @$ns3 walled.tld2 > dig.out.$t
grep -F "EDE: 4 (Forged Answer)" dig.out.$t > /dev/null || setret "failed"
# reload a RPZ zone that is now deliberately broken.
t=`expr $t + 1`
echo_i "checking rpz failed update will keep previous rpz rules (${t})"
@ -860,6 +865,11 @@ EOF
$DIG -p ${PORT} @$ns3 walled.tld2 > dig.out.$t.after
grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.after > /dev/null || setret "failed"
t=`expr $t + 1`
echo_i "checking the default (unset) extended DNS error code (EDE) (${t})"
$DIG -p ${PORT} @$ns3 a6-2.tld2. A > dig.out.$t
grep -F "EDE: " dig.out.$t > /dev/null && setret "failed"
t=`expr $t + 1`
echo_i "checking reload of a mixed-case RPZ zone (${t})"
# First, a sanity check: the A6-2.TLD2.mixed-case-rpz RPZ record should
@ -907,20 +917,25 @@ EOF
grep NXDOMAIN dig.out.${t} > /dev/null || setret "failed"
t=`expr $t + 1`
echo_i "checking that "add-soa no" at rpz zone level works (${t})"
echo_i "checking that 'ede none' works same way as when \"ede\" is unset (${t})"
$DIG z.x.servfail -p ${PORT} @$ns7 > dig.out.${t}
grep -F "EDE: " dig.out.${t} > /dev/null && setret "failed"
t=`expr $t + 1`
echo_i "checking that 'add-soa no' at rpz zone level works (${t})"
$DIG z.x.servfail -p ${PORT} @$ns7 > dig.out.${t}
grep SOA dig.out.${t} > /dev/null && setret "failed"
if [ native = "$mode" ]; then
t=`expr $t + 1`
echo_i "checking that "add-soa yes" at response-policy level works (${t})"
echo_i "checking that 'add-soa yes' at response-policy level works (${t})"
$DIG walled.tld2 -p ${PORT} +noall +add @$ns3 > dig.out.${t}
grep "^manual-update-rpz\..*SOA" dig.out.${t} > /dev/null || setret "failed"
fi
if [ native = "$mode" ]; then
t=`expr $t + 1`
echo_i "checking that "add-soa unset" works (${t})"
echo_i "checking that 'add-soa unset' works (${t})"
$DIG walled.tld2 -p ${PORT} +noall +add @$ns8 > dig.out.${t}
grep "^manual-update-rpz\..*SOA" dig.out.${t} > /dev/null || setret "failed"
fi

View file

@ -5374,6 +5374,35 @@ with this zone file:
example.com CNAME rpz-tcp-only.
*.example.com CNAME rpz-tcp-only.
Response policy zones can be configured to set an Extended DNS Error (EDE) code
on the responses which have been modified by the response policy:
::
response-policy { zone "badlist" ede filtered; };
The following settings are supported for the ``ede`` option:
``none``
No Extended DNS Error code is set (default).
``forged``
Extended DNS Error code 4 - Forged Answer.
``blocked``
Extended DNS Error code 15 - Blocked.
``censored``
Extended DNS Error code 16 - Censored.
``filtered``
Extended DNS Error code 17 - Filtered.
``prohibited``
Extended DNS Error code 18 - Prohibited.
See :rfc:`8914` for more information about the Extended DNS Error codes.
RPZ can affect server performance. Each configured response policy zone
requires the server to perform one to four additional database lookups
before a query can be answered. For example, a DNS server with four

View file

@ -312,7 +312,7 @@ options {
resolver\-query\-timeout <integer>;
resolver\-retry\-interval <integer>;
response\-padding { <address_match_element>; ... } block\-size <integer>;
response\-policy { zone <string> [ add\-soa <boolean> ] [ log <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only <quoted_string> ) ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ]; ... } [ add\-soa <boolean> ] [ break\-dnssec <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ min\-ns\-dots <integer> ] [ nsip\-wait\-recurse <boolean> ] [ nsdname\-wait\-recurse <boolean> ] [ qname\-wait\-recurse <boolean> ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ] [ dnsrps\-enable <boolean> ] [ dnsrps\-options { <unspecified\-text> } ];
response\-policy { zone <string> [ add\-soa <boolean> ] [ log <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only <quoted_string> ) ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ] [ ede <string> ]; ... } [ add\-soa <boolean> ] [ break\-dnssec <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ min\-ns\-dots <integer> ] [ nsip\-wait\-recurse <boolean> ] [ nsdname\-wait\-recurse <boolean> ] [ qname\-wait\-recurse <boolean> ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ] [ dnsrps\-enable <boolean> ] [ dnsrps\-options { <unspecified\-text> } ];
reuseport <boolean>;
root\-delegation\-only [ exclude { <string>; ... } ];
root\-key\-sentinel <boolean>;
@ -590,7 +590,7 @@ view <string> [ <class> ] {
resolver\-query\-timeout <integer>;
resolver\-retry\-interval <integer>;
response\-padding { <address_match_element>; ... } block\-size <integer>;
response\-policy { zone <string> [ add\-soa <boolean> ] [ log <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only <quoted_string> ) ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ]; ... } [ add\-soa <boolean> ] [ break\-dnssec <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ min\-ns\-dots <integer> ] [ nsip\-wait\-recurse <boolean> ] [ nsdname\-wait\-recurse <boolean> ] [ qname\-wait\-recurse <boolean> ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ] [ dnsrps\-enable <boolean> ] [ dnsrps\-options { <unspecified\-text> } ];
response\-policy { zone <string> [ add\-soa <boolean> ] [ log <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only <quoted_string> ) ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ] [ ede <string> ]; ... } [ add\-soa <boolean> ] [ break\-dnssec <boolean> ] [ max\-policy\-ttl <duration> ] [ min\-update\-interval <duration> ] [ min\-ns\-dots <integer> ] [ nsip\-wait\-recurse <boolean> ] [ nsdname\-wait\-recurse <boolean> ] [ qname\-wait\-recurse <boolean> ] [ recursive\-only <boolean> ] [ nsip\-enable <boolean> ] [ nsdname\-enable <boolean> ] [ dnsrps\-enable <boolean> ] [ dnsrps\-options { <unspecified\-text> } ];
root\-delegation\-only [ exclude { <string>; ... } ];
root\-key\-sentinel <boolean>;
rrset\-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };

View file

@ -255,7 +255,7 @@ options {
resolver-query-timeout <integer>;
resolver-retry-interval <integer>;
response-padding { <address_match_element>; ... } block-size <integer>;
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
reuseport <boolean>;
root-delegation-only [ exclude { <string>; ... } ];
root-key-sentinel <boolean>;
@ -533,7 +533,7 @@ view <string> [ <class> ] {
resolver-query-timeout <integer>;
resolver-retry-interval <integer>;
response-padding { <address_match_element>; ... } block-size <integer>;
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
root-delegation-only [ exclude { <string>; ... } ];
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };

View file

@ -16,6 +16,7 @@
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <openssl/opensslv.h>
@ -53,6 +54,7 @@
#include <dns/rbt.h>
#include <dns/rdataclass.h>
#include <dns/rdatatype.h>
#include <dns/rpz.h>
#include <dns/rrl.h>
#include <dns/secalg.h>
#include <dns/ssu.h>
@ -4958,6 +4960,49 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj,
return (result);
}
static isc_result_t
check_rpz(const cfg_obj_t *rpz_obj, isc_log_t *logctx) {
const cfg_listelt_t *element;
const cfg_obj_t *obj, *nameobj, *edeobj;
const char *zonename;
isc_result_t result = ISC_R_SUCCESS, tresult;
dns_fixedname_t fixed;
dns_name_t *name = dns_fixedname_initname(&fixed);
obj = cfg_tuple_get(rpz_obj, "zone list");
for (element = cfg_list_first(obj); element != NULL;
element = cfg_list_next(element))
{
obj = cfg_listelt_value(element);
nameobj = cfg_tuple_get(obj, "zone name");
zonename = cfg_obj_asstring(nameobj);
tresult = dns_name_fromstring(name, zonename, 0, NULL);
if (tresult != ISC_R_SUCCESS) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"bad domain name '%s'", zonename);
if (result == ISC_R_SUCCESS) {
result = tresult;
continue;
}
}
edeobj = cfg_tuple_get(obj, "ede");
if (edeobj != NULL && cfg_obj_isstring(edeobj)) {
const char *str = cfg_obj_asstring(edeobj);
if (dns_rpz_str2ede(str) == UINT16_MAX) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"unsupported EDE type '%s'", str);
result = ISC_R_FAILURE;
}
}
}
return (result);
}
static isc_result_t
check_catz(const cfg_obj_t *catz_obj, const char *viewname, isc_mem_t *mctx,
isc_log_t *logctx) {
@ -5214,6 +5259,19 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
}
}
/*
* Check response-policy configuration.
*/
if (opts != NULL) {
obj = NULL;
if ((cfg_map_get(opts, "response-policy", &obj) ==
ISC_R_SUCCESS) &&
(check_rpz(obj, logctx) != ISC_R_SUCCESS))
{
result = ISC_R_FAILURE;
}
}
/*
* Check catalog-zones configuration.
*/

View file

@ -143,6 +143,7 @@ struct dns_rpz_zone {
dns_name_t cname; /* override value for ..._CNAME */
dns_ttl_t max_policy_ttl;
dns_rpz_policy_t policy; /* DNS_RPZ_POLICY_GIVEN or override */
uint16_t ede; /* Extended DNS Error */
uint32_t min_update_interval; /* minimal interval between
* updates */
@ -379,6 +380,9 @@ dns_rpz_str2policy(const char *str);
const char *
dns_rpz_policy2str(dns_rpz_policy_t policy);
uint16_t
dns_rpz_str2ede(const char *str);
dns_rpz_policy_t
dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset,
dns_name_t *selfname);

View file

@ -15,6 +15,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <isc/buffer.h>
@ -278,6 +279,32 @@ dns_rpz_policy2str(dns_rpz_policy_t policy) {
return (str);
}
uint16_t
dns_rpz_str2ede(const char *str) {
static struct {
const char *str;
uint16_t ede;
} tbl[] = {
{ "none", 0 },
{ "forged", DNS_EDE_FORGEDANSWER },
{ "blocked", DNS_EDE_BLOCKED },
{ "censored", DNS_EDE_CENSORED },
{ "filtered", DNS_EDE_FILTERED },
{ "prohibited", DNS_EDE_PROHIBITED },
};
unsigned int n;
if (str == NULL) {
return (UINT16_MAX);
}
for (n = 0; n < sizeof(tbl) / sizeof(tbl[0]); ++n) {
if (!strcasecmp(tbl[n].str, str)) {
return (tbl[n].ede);
}
}
return (UINT16_MAX);
}
/*
* Return the bit number of the highest set bit in 'zbit'.
* (for example, 0x01 returns 0, 0xFF returns 7, etc.)

View file

@ -1833,6 +1833,7 @@ static cfg_tuplefielddef_t rpz_zone_fields[] = {
{ "recursive-only", &cfg_type_boolean, 0 },
{ "nsip-enable", &cfg_type_boolean, 0 },
{ "nsdname-enable", &cfg_type_boolean, 0 },
{ "ede", &cfg_type_ustring, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_rpz_tuple = { "rpz tuple", cfg_parse_kv_tuple,

View file

@ -16,6 +16,7 @@
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <isc/hex.h>
@ -7267,6 +7268,12 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) {
UNREACHABLE();
}
if (qctx->rpz_st->m.rpz->ede != 0 &&
qctx->rpz_st->m.rpz->ede != UINT16_MAX) {
ns_client_extendederror(qctx->client,
qctx->rpz_st->m.rpz->ede, NULL);
}
/*
* Turn off DNSSEC because the results of a
* response policy zone cannot verify.