2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

Add test for RPZ in multiple views

This adds rudimentary test for response-policy zones in multiple
views.  Different combinations are tested:

- two views with response-policy inherited from options {};
- two views view explicit response-policy using same RPZ zone name
- two views view explicit response-policy using secondary RPZ zone
This commit is contained in:
Ondřej Surý
2023-03-22 15:11:17 +01:00
parent 3b1756d450
commit 1649c768e9
15 changed files with 423 additions and 78 deletions

View File

@@ -18,3 +18,4 @@ rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns*/rpz*.txt
rm -rf __pycache__
rm -f ns3/*-rpz-external.local.db

View File

@@ -1,74 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.1;
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
port @PORT@;
listen-on { 10.53.0.1; };
pid-file "named.pid";
notify no;
dnssec-validation no;
allow-query { any; };
recursion yes;
allow-recursion { any; };
response-policy {
zone "rpz.local";
};
};
logging {
channel rpz_passthru {
file "rpz_passthru.txt" versions 3 size 5m;
print-time yes;
print-category yes;
print-severity yes;
severity info;
};
channel rpz_log {
file "rpz.txt" versions 3 size 20m;
print-time yes;
print-category yes;
print-severity yes;
severity info;
};
category rpz { rpz_log; default_debug; };
category rpz-passthru { rpz_passthru; default_debug; };
};
zone "rpz.local" {
type primary;
file "rpz.local.db";
allow-transfer { none; };
allow-query { localhost; };
};
zone "." {
type hint;
file "root.db";
};

View File

@@ -0,0 +1,27 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; 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 https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA ns1 root.gooddomain. (
2020040101
4h
1h
1w
60
)
IN NS ns1
ns1 IN A 10.53.0.2
gooddomain. IN A 10.53.0.2
www IN A 10.53.0.3

View File

@@ -44,3 +44,14 @@ zone "baddomain" {
allow-transfer { none; };
};
zone "gooddomain" {
type primary;
file "gooddomain.db";
allow-transfer { none; };
};
zone "rpz-external.local" {
type primary;
file "rpz-external.local.db";
allow-transfer { any; };
};

View File

@@ -0,0 +1,26 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; 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 https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA localhost.rpz-external.local root.rpz-external.local. (
2020022500 ; serial number
60 ; refresh every minute
60 ; retry every minute
432000 ; expire in 5 days
60 ; negative caching ttl, 1 minute
)
IN NS LOCALHOST.
allowed IN CNAME .
*.allowed IN CNAME .

View File

@@ -0,0 +1,29 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; 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 https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA localhost.rpz.local root.rpz.local. (
2020022500 ; serial number
60 ; refresh every minute
60 ; retry every minute
432000 ; expire in 5 days
60 ; negative caching ttl, 1 minute
)
IN NS LOCALHOST.
allowed IN CNAME rpz-passthru.
*.allowed IN CNAME rpz-passthru.
gooddomain IN CNAME .
*.gooddomain IN CNAME .

View File

@@ -0,0 +1,32 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; 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 https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA localhost.rpz-extra.local root.rpz-extra.local. (
2020022500 ; serial number
60 ; refresh every minute
60 ; retry every minute
432000 ; expire in 5 days
60 ; negative caching ttl, 1 minute
)
IN NS LOCALHOST.
allowed IN CNAME rpz-passthru.
*.allowed IN CNAME rpz-passthru.
gooddomain IN CNAME .
*.gooddomain IN CNAME .
baddomain IN CNAME .
*.baddomain IN CNAME .

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* 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 https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
listen-on { 10.53.0.3; };
pid-file "named.pid";
notify no;
dnssec-validation no;
allow-query { any; };
recursion yes;
allow-recursion { any; };
empty-zones-enable false;
response-policy {
zone "rpz-extra.local";
};
};
logging {
channel rpz_passthru {
file "rpz_passthru.txt" versions 3 size 5m;
print-time yes;
print-category yes;
print-severity yes;
severity info;
};
channel rpz_log {
file "rpz.txt" versions 3 size 20m;
print-time yes;
print-category yes;
print-severity yes;
severity info;
};
category rpz { rpz_log; default_debug; };
category rpz-passthru { rpz_passthru; default_debug; };
};
view "first" {
match-clients { 10.53.0.1; };
zone "." {
type hint;
file "root.db";
};
zone "rpz.local" {
type primary;
file "first-rpz.local.db";
allow-transfer { none; };
allow-query { localhost; };
};
response-policy {
zone "rpz.local";
};
};
view "second" {
match-clients { 10.53.0.2; };
zone "." {
type hint;
file "root.db";
};
zone "rpz-external.local" {
type secondary;
primaries { 10.53.0.2; };
file "second-rpz-external.local.db";
allow-query { 10.53.0.2; };
};
response-policy {
zone "rpz-external.local";
};
};
view "third" {
match-clients { 10.53.0.3; };
zone "." {
type hint;
file "root.db";
};
zone "rpz-extra.local" {
type primary;
file "third-rpz-extra.local.db";
allow-transfer { none; };
allow-query { localhost; };
};
};
view "fourth" {
match-clients { 10.53.0.4; };
zone "." {
type hint;
file "root.db";
};
zone "rpz-extra.local" {
type primary;
file "fourth-rpz-extra.local.db";
allow-transfer { none; };
allow-query { localhost; };
};
};
view "external" {
match-clients { any; };
zone "." {
type hint;
file "root.db";
};
zone "rpz.local" {
type primary;
file "external-rpz.local.db";
allow-transfer { none; };
allow-query { localhost; };
};
zone "rpz-external.local" {
type secondary;
masterfile-format text;
primaries { 10.53.0.2; };
file "external-rpz-external.local.db";
allow-query { 10.53.0.5; };
};
response-policy {
zone "rpz-external.local";
zone "rpz.local";
};
};

View File

@@ -25,3 +25,6 @@ ns1.allowed. A 10.53.0.2
baddomain. NS ns1.baddomain.
ns1.baddomain. A 10.53.0.2
gooddomain. NS ns1.gooddomain.
ns1.gooddomain. A 10.53.0.2

View File

@@ -0,0 +1,26 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; 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 https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
@ IN SOA localhost.rpz-extra.local root.rpz-extra.local. (
2020022500 ; serial number
60 ; refresh every minute
60 ; retry every minute
432000 ; expire in 5 days
60 ; negative caching ttl, 1 minute
)
IN NS LOCALHOST.
allowed IN CNAME rpz-passthru.
*.allowed IN CNAME rpz-passthru.

View File

@@ -17,5 +17,5 @@ set -e
. ../conf.sh
copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf

View File

@@ -0,0 +1,117 @@
#!/usr/bin/python3
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# 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 https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
import time
import pytest
pytest.importorskip("dns")
import dns.resolver
def wait_for_transfer(ip, port, client_ip, name, rrtype):
resolver = dns.resolver.Resolver()
resolver.nameservers = [ip]
resolver.port = port
for _ in range(10):
try:
resolver.resolve(name, rrtype, source=client_ip)
except dns.resolver.NoNameservers:
time.sleep(1)
else:
break
else:
raise RuntimeError(
"zone transfer failed: "
f"client {client_ip} got NXDOMAIN for {name} {rrtype} from @{ip}:{port}")
def test_rpz_multiple_views(named_port):
resolver = dns.resolver.Resolver()
resolver.nameservers = ["10.53.0.3"]
resolver.port = named_port
wait_for_transfer("10.53.0.3", named_port, "10.53.0.2", "rpz-external.local", "SOA")
wait_for_transfer("10.53.0.3", named_port, "10.53.0.5", "rpz-external.local", "SOA")
# For 10.53.0.1 source IP:
# - baddomain.com isn't allowed (CNAME .), should return NXDOMAIN
# - gooddomain.com is allowed
# - allowed. is allowed
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("baddomain.", "A", source="10.53.0.1")
ans = resolver.resolve("gooddomain.", "A", source="10.53.0.1")
for rd in ans:
assert rd.address == "10.53.0.2"
ans = resolver.resolve("allowed.", "A", source="10.53.0.1")
assert ans[0].address == "10.53.0.2"
# For 10.53.0.2 source IP:
# - allowed.com isn't allowed (CNAME .), should return NXDOMAIN
# - baddomain.com is allowed
# - gooddomain.com is allowed
ans = resolver.resolve("baddomain.", "A", source="10.53.0.2")
for rd in ans:
assert rd.address == "10.53.0.2"
ans = resolver.resolve("gooddomain.", "A", source="10.53.0.2")
for rd in ans:
assert rd.address == "10.53.0.2"
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("allowed.", "A", source="10.53.0.2")
# For 10.53.0.3 source IP:
# - gooddomain.com is allowed
# - baddomain.com is allowed
# - allowed. is allowed
ans = resolver.resolve("baddomain.", "A", source="10.53.0.3")
for rd in ans:
assert rd.address == "10.53.0.2"
ans = resolver.resolve("gooddomain.", "A", source="10.53.0.3")
for rd in ans:
assert rd.address == "10.53.0.2"
ans = resolver.resolve("allowed.", "A", source="10.53.0.3")
assert ans[0].address == "10.53.0.2"
# For 10.53.0.4 source IP:
# - gooddomain.com isn't allowed (CNAME .), should return NXDOMAIN
# - baddomain.com isn't allowed (CNAME .), should return NXDOMAIN
# - allowed. is allowed
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("baddomain.", "A", source="10.53.0.4")
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("gooddomain.", "A", source="10.53.0.4")
ans = resolver.resolve("allowed.", "A", source="10.53.0.4")
assert ans[0].address == "10.53.0.2"
# For 10.53.0.5 (any) source IP:
# - baddomain.com is allowed
# - gooddomain.com isn't allowed (CNAME .), should return NXDOMAIN
# - allowed.com isn't allowed (CNAME .), should return NXDOMAIN
ans = resolver.resolve("baddomain.", "A", source="10.53.0.5")
for rd in ans:
assert rd.address == "10.53.0.2"
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("gooddomain.", "A", source="10.53.0.5")
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("allowed.", "A", source="10.53.0.5")

View File

@@ -21,7 +21,7 @@ import dns.resolver
def test_rpz_passthru_logging(named_port):
resolver = dns.resolver.Resolver()
resolver.nameservers = ["10.53.0.1"]
resolver.nameservers = ["10.53.0.3"]
resolver.port = named_port
# Should generate a log entry into rpz_passthru.txt
@@ -34,8 +34,8 @@ def test_rpz_passthru_logging(named_port):
with pytest.raises(dns.resolver.NXDOMAIN):
resolver.resolve("baddomain.", "A", source="10.53.0.1")
rpz_passthru_logfile = os.path.join("ns1", "rpz_passthru.txt")
rpz_logfile = os.path.join("ns1", "rpz.txt")
rpz_passthru_logfile = os.path.join("ns3", "rpz_passthru.txt")
rpz_logfile = os.path.join("ns3", "rpz.txt")
assert os.path.isfile(rpz_passthru_logfile)
assert os.path.isfile(rpz_logfile)