diff --git a/CHANGES b/CHANGES index c6a8e3d72f..e53d3994cc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +5177. [func] Add the ability to specify in named.conf whether a + response-policy zone's SOA record should be added + to the additional section (add-soa yes/no). [GL #865] + 5176. [tests] Remove a dependency on libxml in statschannel system test. [GL #926] diff --git a/bin/named/server.c b/bin/named/server.c index 48c5aab8b9..ca64b9dffe 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -2115,6 +2115,7 @@ configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name, static isc_result_t configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element, bool recursive_only_default, + bool add_soa_default, dns_ttl_t ttl_default, uint32_t minupdateinterval_default, const dns_rpz_zone_t *old, @@ -2259,6 +2260,13 @@ configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element, !dns_name_equal(&old->cname, &zone->cname))) *old_rpz_okp = false; + obj = cfg_tuple_get(rpz_obj, "add-soa"); + if (cfg_obj_isvoid(obj)) { + zone->addsoa = add_soa_default; + } else { + zone->addsoa = cfg_obj_asboolean(obj); + } + return (ISC_R_SUCCESS); } @@ -2271,7 +2279,7 @@ configure_rpz(dns_view_t *view, const cfg_obj_t **maps, char *rps_cstr; size_t rps_cstr_size; const cfg_obj_t *sub_obj; - bool recursive_only_default; + bool recursive_only_default, add_soa_default; bool nsip_enabled, nsdname_enabled; dns_rpz_zbits_t nsip_on, nsdname_on; dns_ttl_t ttl_default; @@ -2367,6 +2375,13 @@ configure_rpz(dns_view_t *view, const cfg_obj_t **maps, recursive_only_default = true; } + sub_obj = cfg_tuple_get(rpz_obj, "add-soa"); + if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) { + add_soa_default = false; + } else { + add_soa_default = true; + } + sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec"); if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) { zones->p.break_dnssec = true; @@ -2429,6 +2444,7 @@ configure_rpz(dns_view_t *view, const cfg_obj_t **maps, } result = configure_rpz_zone(view, zone_element, recursive_only_default, + add_soa_default, ttl_default, minupdateinterval_default, old_zone, old_rpz_okp); diff --git a/bin/tests/system/rpz/clean.sh b/bin/tests/system/rpz/clean.sh index e0bdf5a74c..bd21c9607c 100644 --- a/bin/tests/system/rpz/clean.sh +++ b/bin/tests/system/rpz/clean.sh @@ -32,6 +32,7 @@ rm -f ns2/tld2s.db ns2/bl.tld2.db rm -f ns3/bl*.db ns*/empty.db rm -f ns3/manual-update-rpz.db rm -f ns5/example.db ns5/bl.db +rm -f ns8/manual-update-rpz.db rm -f */policy2.db rm -f */*.jnl diff --git a/bin/tests/system/rpz/ns3/manual-update-rpz.db.in b/bin/tests/system/rpz/ns3/manual-update-rpz.db.in index 81fa1f0754..0a15b611db 100644 --- a/bin/tests/system/rpz/ns3/manual-update-rpz.db.in +++ b/bin/tests/system/rpz/ns3/manual-update-rpz.db.in @@ -17,4 +17,3 @@ $TTL 300 NS ns.tld3. walled.tld2.manual-update-rpz. 300 A 10.0.0.1 - diff --git a/bin/tests/system/rpz/ns3/named.conf.in b/bin/tests/system/rpz/ns3/named.conf.in index bd1a7103c3..8e6e1456da 100644 --- a/bin/tests/system/rpz/ns3/named.conf.in +++ b/bin/tests/system/rpz/ns3/named.conf.in @@ -46,6 +46,7 @@ options { zone "bl.tld2"; zone "manual-update-rpz"; } + add-soa yes min-ns-dots 0 qname-wait-recurse yes min-update-interval 0 diff --git a/bin/tests/system/rpz/ns6/named.conf.in b/bin/tests/system/rpz/ns6/named.conf.in index 71391ac885..c34546dc47 100644 --- a/bin/tests/system/rpz/ns6/named.conf.in +++ b/bin/tests/system/rpz/ns6/named.conf.in @@ -29,6 +29,7 @@ options { response-policy { zone "policy1" min-update-interval 0; } qname-wait-recurse yes + // add-soa yes # leave add-soa as default for unset test nsip-enable yes nsdname-enable yes; diff --git a/bin/tests/system/rpz/ns7/named.conf.in b/bin/tests/system/rpz/ns7/named.conf.in index 842f709923..f92b01c06c 100644 --- a/bin/tests/system/rpz/ns7/named.conf.in +++ b/bin/tests/system/rpz/ns7/named.conf.in @@ -24,7 +24,7 @@ options { dnssec-validation yes; response-policy { - zone "policy2"; + zone "policy2" add-soa no; } qname-wait-recurse no nsip-enable yes nsdname-enable yes diff --git a/bin/tests/system/rpz/ns8/hints b/bin/tests/system/rpz/ns8/hints new file mode 100644 index 0000000000..28e5850c4f --- /dev/null +++ b/bin/tests/system/rpz/ns8/hints @@ -0,0 +1,11 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +. 120 NS ns. +ns. 120 A 10.53.0.1 diff --git a/bin/tests/system/rpz/ns8/manual-update-rpz.db.in b/bin/tests/system/rpz/ns8/manual-update-rpz.db.in new file mode 100644 index 0000000000..0a15b611db --- /dev/null +++ b/bin/tests/system/rpz/ns8/manual-update-rpz.db.in @@ -0,0 +1,19 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; 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 http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +; RPZ test +; This basic file is copied to several zone files before being used. +; Its contents are also changed with nsupdate + + +$TTL 300 +@ SOA manual-update-rpz. hostmaster.ns.manual-rpz-update. ( 1 3600 1200 604800 60 ) + NS ns.tld3. + +walled.tld2.manual-update-rpz. 300 A 10.0.0.1 diff --git a/bin/tests/system/rpz/ns8/named.conf.in b/bin/tests/system/rpz/ns8/named.conf.in new file mode 100644 index 0000000000..430ca14198 --- /dev/null +++ b/bin/tests/system/rpz/ns8/named.conf.in @@ -0,0 +1,65 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + + +/* + * Main rpz test DNS server. + */ + +options { + query-source address 10.53.0.8; + notify-source 10.53.0.8; + transfer-source 10.53.0.8; + port @PORT@; + pid-file "named.pid"; + statistics-file "named.stats"; + session-keyfile "session.key"; + listen-on { 10.53.0.8; }; + listen-on-v6 { none; }; + notify yes; + minimal-responses no; + recursion yes; + dnssec-validation yes; + + response-policy { + zone "manual-update-rpz"; + } + // add-soa yes // do not set testing default mode + min-ns-dots 0 + qname-wait-recurse yes + min-update-interval 0 + nsdname-enable yes + nsip-enable yes + ; + + include "../dnsrps.conf"; + also-notify { 10.53.0.8 port @EXTRAPORT1@; }; + notify-delay 0; +}; + +logging { category rpz { default_debug; }; }; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; +controls { + inet 10.53.0.8 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + + +zone "." { type hint; file "hints"; }; + +zone "manual-update-rpz." { + type master; + file "manual-update-rpz.db"; + notify no; +}; diff --git a/bin/tests/system/rpz/setup.sh b/bin/tests/system/rpz/setup.sh index 4b7e793824..4dd89d38c7 100644 --- a/bin/tests/system/rpz/setup.sh +++ b/bin/tests/system/rpz/setup.sh @@ -50,6 +50,7 @@ copy_setports ns4/named.conf.in ns4/named.conf copy_setports ns5/named.conf.in ns5/named.conf copy_setports ns6/named.conf.in ns6/named.conf copy_setports ns7/named.conf.in ns7/named.conf +copy_setports ns8/named.conf.in ns8/named.conf copy_setports dnsrpzd.conf.in dnsrpzd.conf @@ -70,6 +71,7 @@ for NM in '' -2 -given -disabled -passthru -no-op -nodata -nxdomain -cname -wild done # bl zones are dynamically updated. Add one zone that is updated manually. cp ns3/manual-update-rpz.db.in ns3/manual-update-rpz.db +cp ns8/manual-update-rpz.db.in ns8/manual-update-rpz.db # $1=directory # $2=domain name diff --git a/bin/tests/system/rpz/tests.sh b/bin/tests/system/rpz/tests.sh index b6ba574360..1a035dc486 100644 --- a/bin/tests/system/rpz/tests.sh +++ b/bin/tests/system/rpz/tests.sh @@ -25,6 +25,7 @@ ns4=$ns.4 # another authoritative server that is rewritten ns5=$ns.5 # another rewriting resolver ns6=$ns.6 # a forwarding server ns7=$ns.7 # another rewriting resolver +ns8=$ns.8 # another rewriting resolver HAVE_CORE= @@ -776,27 +777,29 @@ EOF fi done - # restart the main test RPZ server with a bad zone. - t=`expr $t + 1` - echo_i "checking that ns3 with broken rpz does not crash (${t})" - $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3 - cp ns3/broken.db.in ns3/bl.db - restart 3 # do not rebuild rpz zones - nocrash a3-1.tld2 -tA - $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3 - restart 3 "rebuild-bl-rpz" + if [ native = "$mode" ]; then + # restart the main test RPZ server with a bad zone. + t=`expr $t + 1` + echo_i "checking that ns3 with broken rpz does not crash (${t})" + $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3 + cp ns3/broken.db.in ns3/bl.db + restart 3 # do not rebuild rpz zones + nocrash a3-1.tld2 -tA + $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} rpz ns3 + restart 3 "rebuild-bl-rpz" - # 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})" - $DIG -p ${PORT} @$ns3 walled.tld2 > dig.out.$t.before - grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.before > /dev/null || setret "failed" - cp ns3/broken.db.in ns3/manual-update-rpz.db - rndc_reload ns3 $ns3 manual-update-rpz - sleep 1 - # ensure previous RPZ rules still apply. - $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" + # 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})" + $DIG -p ${PORT} @$ns3 walled.tld2 > dig.out.$t.before + grep "walled\.tld2\..*IN.*A.*10\.0\.0\.1" dig.out.$t.before > /dev/null || setret "failed" + cp ns3/broken.db.in ns3/manual-update-rpz.db + rndc_reload ns3 $ns3 manual-update-rpz + sleep 1 + # ensure previous RPZ rules still apply. + $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" + fi t=`expr $t + 1` echo_i "checking that ttl values are not zeroed when qtype is '*' (${t})" @@ -825,9 +828,28 @@ EOF $DIG z.x.servfail -p ${PORT} @$ns7 > dig.out.${t} 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})" + $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})" + $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})" + $DIG walled.tld2 -p ${PORT} +noall +add @$ns8 > dig.out.${t} + grep "^manual-update-rpz\..*SOA" dig.out.${t} > /dev/null || setret "failed" + fi + # dnsrps does not allow NS RRs in policy zones, so this check # with dnsrps results in no rewriting. - if [ "$mode" = native ]; then + if [ native = "$mode" ]; then t=`expr $t + 1` echo_i "checking rpz with delegation fails correctly (${t})" $DIG -p ${PORT} @$ns3 ns example.com > dig.out.$t diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 8ecef87d3a..33d7499f0e 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -10133,6 +10133,14 @@ example.com CNAME rpz-tcp-only. zone. By default, all rewrites are logged. + + The add-soa option controls whether the RPZ's + SOA record is added to the additional section for traceback + of changes from this zone or not. This can be set at the + individual policy zone level or at the response-policy level. + The default is yes. + + Updates to RPZ zones are processed asynchronously; if there is more than one update pending they are bundled together. diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 3dc8716a07..5d1a0e0792 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -97,7 +97,10 @@ - None. + The new add-soa option specifies whether + or not the response-policy zone's SOA record + should be included in the additional section of RPZ responses. + [GL #865] diff --git a/doc/misc/options b/doc/misc/options index 9713c104dd..5be0c3a722 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -186,7 +186,7 @@ options { fstrm-set-output-queue-model ( mpsc | spsc ); // not configured fstrm-set-output-queue-size ; // not configured fstrm-set-reopen-interval ; // not configured - geoip-directory ( | none ); // not configured + geoip-directory ( | none ); geoip-use-ecs ; // obsolete glue-cache ; has-old-clients ; // ancient @@ -207,7 +207,7 @@ options { listen-on-v6 [ port ] [ dscp ] { ; ... }; // may occur multiple times - lmdb-mapsize ; // non-operational + lmdb-mapsize ; lock-file ( | none ); maintain-ixfr-base ; // ancient managed-keys-directory ; @@ -310,11 +310,12 @@ options { resolver-retry-interval ; response-padding { ; ... } block-size ; - response-policy { zone [ 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 ]; ... } [ + 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 ] [ qname-wait-recurse ] @@ -552,7 +553,7 @@ view [ ] { }; // may occur multiple times key-directory ; lame-ttl ; - lmdb-mapsize ; // non-operational + lmdb-mapsize ; maintain-ixfr-base ; // ancient managed-keys { @@ -647,11 +648,12 @@ view [ ] { resolver-retry-interval ; response-padding { ; ... } block-size ; - response-policy { zone [ 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 ]; ... } [ + 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 ] [ qname-wait-recurse ] diff --git a/lib/dns/include/dns/rpz.h b/lib/dns/include/dns/rpz.h index e8f5170ca7..612a543e5f 100644 --- a/lib/dns/include/dns/rpz.h +++ b/lib/dns/include/dns/rpz.h @@ -144,14 +144,16 @@ struct dns_rpz_zone { isc_ht_t *nodes; /* entries in zone */ dns_rpz_zones_t *rpzs; /* owner */ isc_time_t lastupdated; /* last time the zone was processed */ - bool updatepending; /* there is an update pending/waiting */ - bool updaterunning; /* there is an update running */ + bool updatepending; /* there is an update pending/waiting */ + bool updaterunning; /* there is an update running */ dns_db_t *db; /* zones database */ dns_dbversion_t *dbversion; /* version we will be updating to */ dns_db_t *updb; /* zones database we're working on */ dns_dbversion_t *updbversion; /* version we're currently working on */ dns_dbiterator_t *updbit; /* iterator to use when updating */ isc_ht_t *newnodes; /* entries in zone being updated */ + bool db_registered; /* is the notify event registered? */ + bool addsoa; /* add soa to the additional section */ isc_timer_t *updatetimer; isc_event_t updateevent; }; @@ -190,10 +192,10 @@ struct dns_rpz_popt { dns_rpz_zbits_t no_log; dns_rpz_zbits_t nsip_on; dns_rpz_zbits_t nsdname_on; - bool dnsrps_enabled; - bool break_dnssec; - bool qname_wait_recurse; - bool nsip_wait_recurse; + bool dnsrps_enabled; + bool break_dnssec; + bool qname_wait_recurse; + bool nsip_wait_recurse; unsigned int min_ns_labels; dns_rpz_num_t num_zones; }; @@ -311,8 +313,8 @@ typedef struct { */ struct { isc_result_t result; - bool is_zone; - bool authoritative; + bool is_zone; + bool authoritative; dns_zone_t *zone; dns_db_t *db; dns_dbnode_t *node; @@ -423,4 +425,3 @@ dns_rpz_find_name(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type, ISC_LANG_ENDDECLS #endif /* DNS_RPZ_H */ - diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index 83f8f7d6c5..e6e2f3ab42 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -1549,6 +1549,8 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { zone->updbversion = NULL; zone->updbit = NULL; zone->rpzs = rpzs; + zone->db_registered = false; + zone->addsoa = true; ISC_EVENT_INIT(&zone->updateevent, sizeof(zone->updateevent), 0, NULL, 0, NULL, NULL, NULL, NULL, NULL); diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 6f88a4cba3..8a3aaf3367 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -1604,6 +1604,7 @@ static cfg_type_t cfg_type_rpz_policy = { }; static cfg_tuplefielddef_t rpz_zone_fields[] = { { "zone name", &cfg_type_rpz_zone, 0 }, + { "add-soa", &cfg_type_boolean, 0 }, { "log", &cfg_type_boolean, 0 }, { "max-policy-ttl", &cfg_type_ttlval, 0 }, { "min-update-interval", &cfg_type_ttlval, 0 }, @@ -1625,6 +1626,7 @@ static cfg_type_t cfg_type_rpz_list = { }; static cfg_tuplefielddef_t rpz_fields[] = { { "zone list", &cfg_type_rpz_list, 0 }, + { "add-soa", &cfg_type_boolean, 0 }, { "break-dnssec", &cfg_type_boolean, 0 }, { "max-policy-ttl", &cfg_type_ttlval, 0 }, { "min-update-interval", &cfg_type_ttlval, 0 }, diff --git a/lib/ns/query.c b/lib/ns/query.c index 0efcafd578..7f8722471e 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -6227,12 +6227,15 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) { /* * Add SOA record to additional section */ - rresult = query_addsoa(qctx, - dns_rdataset_isassociated(qctx->rdataset), - DNS_SECTION_ADDITIONAL); - if (rresult != ISC_R_SUCCESS) { - QUERY_ERROR(qctx, result); - return (ISC_R_COMPLETE); + if (qctx->rpz_st->m.rpz->addsoa) { + bool override_ttl = + dns_rdataset_isassociated(qctx->rdataset); + rresult = query_addsoa(qctx, override_ttl, + DNS_SECTION_ADDITIONAL); + if (rresult != ISC_R_SUCCESS) { + QUERY_ERROR(qctx, result); + return (ISC_R_COMPLETE); + } } switch (qctx->rpz_st->m.policy) { @@ -8375,10 +8378,12 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { { ttl = 0; } - result = query_addsoa(qctx, ttl, section); - if (result != ISC_R_SUCCESS) { - QUERY_ERROR(qctx, result); - return (ns_query_done(qctx)); + if (!qctx->nxrewrite || qctx->rpz_st->m.rpz->addsoa) { + result = query_addsoa(qctx, ttl, section); + if (result != ISC_R_SUCCESS) { + QUERY_ERROR(qctx, result); + return (ns_query_done(qctx)); + } } if (WANTDNSSEC(qctx->client)) {