commit 01cd077f55435ff34e0604e05cf0fbf898799697
Author: Tomas Korbar <tkorbar@redhat.com>
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;