From 77f12ecba7dfbfb4abfb063d4206cc9795ce589d Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Fri, 26 Aug 2022 14:11:47 +0000 Subject: [PATCH] Add extended DNS error configuration option for RPZ zones Implement the configuration option with its checking and parsing parts. The option should be later used by BIND to set an extended error code (EDE) for the queries modified in the result of RPZ processing. --- bin/named/server.c | 13 +++++++++ doc/man/named.conf.5in | 4 +-- doc/misc/options | 4 +-- lib/bind9/check.c | 58 +++++++++++++++++++++++++++++++++++++++ lib/dns/include/dns/rpz.h | 4 +++ lib/dns/rpz.c | 27 ++++++++++++++++++ lib/isccfg/namedconf.c | 1 + 7 files changed, 107 insertions(+), 4 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 899b0e027a..476c408b78 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/doc/man/named.conf.5in b/doc/man/named.conf.5in index cbc565134c..47ef15b08e 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -312,7 +312,7 @@ options { resolver\-query\-timeout ; resolver\-retry\-interval ; response\-padding { ; ... } block\-size ; - response\-policy { zone [ add\-soa ] [ log ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only ) ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ]; ... } [ add\-soa ] [ break\-dnssec ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ min\-ns\-dots ] [ nsip\-wait\-recurse ] [ nsdname\-wait\-recurse ] [ qname\-wait\-recurse ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ] [ dnsrps\-enable ] [ dnsrps\-options { } ]; + response\-policy { zone [ add\-soa ] [ log ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only ) ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ] [ ede ]; ... } [ add\-soa ] [ break\-dnssec ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ min\-ns\-dots ] [ nsip\-wait\-recurse ] [ nsdname\-wait\-recurse ] [ qname\-wait\-recurse ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ] [ dnsrps\-enable ] [ dnsrps\-options { } ]; reuseport ; root\-delegation\-only [ exclude { ; ... } ]; root\-key\-sentinel ; @@ -590,7 +590,7 @@ view [ ] { resolver\-query\-timeout ; resolver\-retry\-interval ; response\-padding { ; ... } block\-size ; - response\-policy { zone [ add\-soa ] [ log ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only ) ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ]; ... } [ add\-soa ] [ break\-dnssec ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ min\-ns\-dots ] [ nsip\-wait\-recurse ] [ nsdname\-wait\-recurse ] [ qname\-wait\-recurse ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ] [ dnsrps\-enable ] [ dnsrps\-options { } ]; + response\-policy { zone [ add\-soa ] [ log ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ policy ( cname | disabled | drop | given | no\-op | nodata | nxdomain | passthru | tcp\-only ) ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ] [ ede ]; ... } [ add\-soa ] [ break\-dnssec ] [ max\-policy\-ttl ] [ min\-update\-interval ] [ min\-ns\-dots ] [ nsip\-wait\-recurse ] [ nsdname\-wait\-recurse ] [ qname\-wait\-recurse ] [ recursive\-only ] [ nsip\-enable ] [ nsdname\-enable ] [ dnsrps\-enable ] [ dnsrps\-options { } ]; root\-delegation\-only [ exclude { ; ... } ]; root\-key\-sentinel ; rrset\-order { [ class ] [ type ] [ name ] ; ... }; diff --git a/doc/misc/options b/doc/misc/options index 1681be1514..6b0609394f 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -255,7 +255,7 @@ options { resolver-query-timeout ; resolver-retry-interval ; response-padding { ; ... } block-size ; - response-policy { zone [ add-soa ] [ log ] [ max-policy-ttl ] [ min-update-interval ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only ) ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ]; ... } [ add-soa ] [ break-dnssec ] [ max-policy-ttl ] [ min-update-interval ] [ min-ns-dots ] [ nsip-wait-recurse ] [ nsdname-wait-recurse ] [ qname-wait-recurse ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ] [ dnsrps-enable ] [ dnsrps-options { } ]; + response-policy { zone [ add-soa ] [ log ] [ max-policy-ttl ] [ min-update-interval ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only ) ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ] [ ede ]; ... } [ add-soa ] [ break-dnssec ] [ max-policy-ttl ] [ min-update-interval ] [ min-ns-dots ] [ nsip-wait-recurse ] [ nsdname-wait-recurse ] [ qname-wait-recurse ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ] [ dnsrps-enable ] [ dnsrps-options { } ]; reuseport ; root-delegation-only [ exclude { ; ... } ]; root-key-sentinel ; @@ -533,7 +533,7 @@ view [ ] { resolver-query-timeout ; resolver-retry-interval ; response-padding { ; ... } block-size ; - response-policy { zone [ add-soa ] [ log ] [ max-policy-ttl ] [ min-update-interval ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only ) ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ]; ... } [ add-soa ] [ break-dnssec ] [ max-policy-ttl ] [ min-update-interval ] [ min-ns-dots ] [ nsip-wait-recurse ] [ nsdname-wait-recurse ] [ qname-wait-recurse ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ] [ dnsrps-enable ] [ dnsrps-options { } ]; + response-policy { zone [ add-soa ] [ log ] [ max-policy-ttl ] [ min-update-interval ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only ) ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ] [ ede ]; ... } [ add-soa ] [ break-dnssec ] [ max-policy-ttl ] [ min-update-interval ] [ min-ns-dots ] [ nsip-wait-recurse ] [ nsdname-wait-recurse ] [ qname-wait-recurse ] [ recursive-only ] [ nsip-enable ] [ nsdname-enable ] [ dnsrps-enable ] [ dnsrps-options { } ]; root-delegation-only [ exclude { ; ... } ]; root-key-sentinel ; rrset-order { [ class ] [ type ] [ name ] ; ... }; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index f24d02c02d..2ddd90b270 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -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. */ diff --git a/lib/dns/include/dns/rpz.h b/lib/dns/include/dns/rpz.h index c46168d538..4bd421b22f 100644 --- a/lib/dns/include/dns/rpz.h +++ b/lib/dns/include/dns/rpz.h @@ -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); diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index 4e78b57609..cfeac54dea 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -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.) diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 64d0ddb494..481bc9827b 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -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,