commit 01cd077f55435ff34e0604e05cf0fbf898799697 Author: Tomas Korbar Date: Fri Sep 25 11:57:56 2020 +0200 Resolve "RPZ wildcard passthru ignored" diff --git a/bin/tests/system/rpzrecurse/ns1/example.com.db b/bin/tests/system/rpzrecurse/ns1/example.com.db new file mode 100644 index 0000000..5bbe973 --- /dev/null +++ b/bin/tests/system/rpzrecurse/ns1/example.com.db @@ -0,0 +1,16 @@ +; 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. + +$TTL 3600 +@ IN SOA ns.example.com. root.example.com. 1 3600 3600 3600 3600 +@ NS ns.example.com. + +ns.example.com. A 10.53.0.1 +@ A 1.2.3.4 +www A 1.2.3.5 diff --git a/bin/tests/system/rpzrecurse/ns1/named.conf.in b/bin/tests/system/rpzrecurse/ns1/named.conf.in index e8105a2..d3ae39f 100644 --- a/bin/tests/system/rpzrecurse/ns1/named.conf.in +++ b/bin/tests/system/rpzrecurse/ns1/named.conf.in @@ -65,3 +65,8 @@ zone "test2.example.net" { type master; file "test2.example.net.db"; }; + +zone "example.com" { + type master; + file "example.com.db"; +}; diff --git a/bin/tests/system/rpzrecurse/ns2/db.given b/bin/tests/system/rpzrecurse/ns2/db.given new file mode 100644 index 0000000..ba78588 --- /dev/null +++ b/bin/tests/system/rpzrecurse/ns2/db.given @@ -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. + +$ORIGIN given.zone. +$TTL 3600 +@ IN SOA ns.given.zone. hostmaster.given.zone. 1 600 300 604800 3600 + IN NS ns.given.zone. + +ns IN A 127.0.0.1 +; this should be ignores as it matches earlier passthru entry. +example.com CNAME . +; this should be ignored as it matches earlier wildcard passthru entry. +www.example.com CNAME . diff --git a/bin/tests/system/rpzrecurse/ns2/db.passthru b/bin/tests/system/rpzrecurse/ns2/db.passthru new file mode 100644 index 0000000..4b0b834 --- /dev/null +++ b/bin/tests/system/rpzrecurse/ns2/db.passthru @@ -0,0 +1,17 @@ +; 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. + +$ORIGIN passthru.zone. +$TTL 3600 +@ IN SOA ns.passthru.zone. hostmaster.passthru.zone. 1 600 300 604800 3600 + IN NS ns.passthru.zone. + +ns IN A 127.0.0.1 +example.com CNAME rpz-passthru. +*.example.com CNAME rpz-passthru. diff --git a/bin/tests/system/rpzrecurse/ns2/named.wildcard4.conf b/bin/tests/system/rpzrecurse/ns2/named.wildcard4.conf new file mode 100644 index 0000000..78915d6 --- /dev/null +++ b/bin/tests/system/rpzrecurse/ns2/named.wildcard4.conf @@ -0,0 +1,33 @@ +/* + * 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. + */ + +# common configuration +include "named.conf.header"; + +view "recursive" { + # policy configuration to be tested + response-policy { + zone "passthru.zone" policy passthru; + zone "given.zone" policy given; + }; + + # policy zones to be tested + zone "passthru.zone" { type master; file "db.passthru"; }; + zone "given.zone" { type master; file "db.given"; }; + + zone "." { + type hint; + file "root.hint"; + }; + + recursion yes; + dnssec-validation yes; +}; diff --git a/bin/tests/system/rpzrecurse/tests.sh b/bin/tests/system/rpzrecurse/tests.sh index 8a23955..5ab2431 100644 --- a/bin/tests/system/rpzrecurse/tests.sh +++ b/bin/tests/system/rpzrecurse/tests.sh @@ -390,5 +390,19 @@ if test $p1 -le $p2; then ret=1; fi if test $ret != 0; then echo_i "failed"; fi status=`expr $status + $ret` +t=`expr $t + 1` +echo_i "testing wildcard passthru before explicit drop (${t})" +run_server wildcard4 +$DIG $DIGOPTS example.com a @10.53.0.2 -p ${PORT} > dig.out.${t}.1 +grep "status: NOERROR" dig.out.${t}.1 > /dev/null || { + echo_i "test ${t} failed" + status=1 +} +$DIG $DIGOPTS www.example.com a @10.53.0.2 -p ${PORT} > dig.out.${t}.2 +grep "status: NOERROR" dig.out.${t}.2 > /dev/null || { + echo_i "test ${t} failed" + status=1 +} + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/bin/tests/system/run.sh b/bin/tests/system/run.sh index a0d8b6d..c528be7 100755 --- a/bin/tests/system/run.sh +++ b/bin/tests/system/run.sh @@ -220,6 +220,8 @@ else elif [ $sanitizer_summaries -ne 0 ]; then echoinfo "I:$systest:Test claims success despite $sanitizer_summaries sanitizer reports(s)" echofail "R:$systest:FAIL" + elif [ "$status" != 0 ]; then + echofail "R:$systest:FAIL" else echopass "R:$systest:PASS" if $clean diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index 3c235c3..b987499 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -2326,7 +2326,40 @@ dns_rpz_find_name(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type, case DNS_R_PARTIALMATCH: i = chain.level_matches; - while (i >= 0 && (nmnode = chain.levels[i]) != NULL) { + nmnode = chain.levels[chain.level_matches]; + + /* Whenever an exact match is found by dns_rbt_findnode(), + * the highest level node in the chain will not be put into + * chain->levels[] array, but instead the chain->end + * pointer will be adjusted to point to that node. + * + * Suppose we have the following entries in a rpz zone: + * example.com CNAME rpz-passthru. + * *.example.com CNAME rpz-passthru. + * + * A query for www.example.com would result in the + * following chain object returned by dns_rbt_findnode(): + * chain->level_count = 2 + * chain->level_matches = 2 + * chain->levels[0] = . + * chain->levels[1] = example.com + * chain->levels[2] = NULL + * chain->end = www + * + * Since exact matches only care for testing rpz set bits, + * we need to test for rpz wild bits through iterating the + * nodechain, and that includes testing the rpz wild bits in the + * highest level node found. In the case of an exact match, + * chain->levels[chain->level_matches] will be NULL, to address + * that we must use chain->end as the start + * point, then iterate over the remaining levels in the chain. + */ + if (nmnode == NULL) { + --i; + nmnode = chain.end; + } + + while (nmnode != NULL) { nm_data = nmnode->data; if (nm_data != NULL) { if (rpz_type == DNS_RPZ_TYPE_QNAME) { @@ -2335,7 +2368,13 @@ dns_rpz_find_name(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type, found_zbits |= nm_data->wild.ns; } } - i--; + + if (i >= 0) { + nmnode = chain.levels[i]; + --i; + } else { + break; + } } break;