Blob Blame History Raw
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;