]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
convert filter-aaaa test to python
authorEvan Hunt <each@isc.org>
Thu, 10 Jul 2025 08:03:17 +0000 (01:03 -0700)
committerEvan Hunt <each@isc.org>
Wed, 6 Aug 2025 06:01:03 +0000 (23:01 -0700)
use pytest for the filter-aaaa test.

In order to implement this, isctest.mark can now test whether IPv6 is
configured by calling testsock6.pl.

24 files changed:
bin/tests/system/filter-aaaa/conf/bad1.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/bad1.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/bad2.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/bad2.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/bad3.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/bad3.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/bad4.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/bad4.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/bad5.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/bad5.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/good1.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/good1.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/good2.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/good2.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/good3.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/good3.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/good4.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/good4.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/conf/good5.conf.j2 [moved from bin/tests/system/filter-aaaa/conf/good5.conf.in with 100% similarity]
bin/tests/system/filter-aaaa/ns1/named.conf.j2 [moved from bin/tests/system/filter-aaaa/ns1/named1.conf.in with 65% similarity]
bin/tests/system/filter-aaaa/ns1/named2.conf.in [deleted file]
bin/tests/system/filter-aaaa/ns2/named.conf.j2 [moved from bin/tests/system/filter-aaaa/ns2/named1.conf.in with 64% similarity]
bin/tests/system/filter-aaaa/ns2/named2.conf.in [deleted file]
bin/tests/system/filter-aaaa/ns3/named.conf.j2 [moved from bin/tests/system/filter-aaaa/ns3/named2.conf.in with 63% similarity]
bin/tests/system/filter-aaaa/ns3/named1.conf.in [deleted file]
bin/tests/system/filter-aaaa/ns4/named.conf.j2 [moved from bin/tests/system/filter-aaaa/ns4/named1.conf.in with 65% similarity]
bin/tests/system/filter-aaaa/ns4/named2.conf.in [deleted file]
bin/tests/system/filter-aaaa/ns5/named.conf.j2 [moved from bin/tests/system/filter-aaaa/ns5/named.conf.in with 84% similarity]
bin/tests/system/filter-aaaa/setup.sh
bin/tests/system/filter-aaaa/tests.sh [deleted file]
bin/tests/system/filter-aaaa/tests_filter_aaaa.py [new file with mode: 0644]
bin/tests/system/filter-aaaa/tests_sh_filter_aaaa.py [deleted file]
bin/tests/system/isctest/mark.py

similarity index 65%
rename from bin/tests/system/filter-aaaa/ns1/named1.conf.in
rename to bin/tests/system/filter-aaaa/ns1/named.conf.j2
index 8dea5f5d226620ce7debc18bc65e5bbf7c02f2c5..e5e76b1ecffffcc5f7f3f320d9ec15d3d2fc3b0c 100644 (file)
@@ -11,6 +11,9 @@
  * information regarding copyright ownership.
  */
 
+{% set filtertype = filtertype | default("aaaa") %}
+{% set family = family | default("v4") %}
+
 options {
        query-source address 10.53.0.1;
        notify-source 10.53.0.1;
@@ -25,13 +28,19 @@ options {
        minimal-responses no;
 };
 
-
-acl filterees { 10.53.0.1; };
-
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v4 yes;
-       filter-aaaa { filterees; };
-};
+{% if family == "v6" %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v6 yes;
+                filter-@filtertype@ { fd92:7065:b8e:ffff::1; };
+        };
+{% else %}
+        acl filterees { 10.53.0.1; };
+
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v4 yes;
+                filter-@filtertype@ { filterees; };
+        };
+{% endif %}
 
 key rndc_key {
        secret "1234abcd8765";
diff --git a/bin/tests/system/filter-aaaa/ns1/named2.conf.in b/bin/tests/system/filter-aaaa/ns1/named2.conf.in
deleted file mode 100644 (file)
index b03fda5..0000000
+++ /dev/null
@@ -1,45 +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.
- */
-
-options {
-       query-source address 10.53.0.1;
-       notify-source 10.53.0.1;
-       transfer-source 10.53.0.1;
-       port @PORT@;
-       pid-file "named.pid";
-       listen-on { 10.53.0.1; };
-       listen-on-v6 { fd92:7065:b8e:ffff::1; };
-       recursion no;
-       dnssec-validation no;
-       notify yes;
-       minimal-responses no;
-};
-
-
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v6 yes;
-       filter-aaaa { fd92:7065:b8e:ffff::1; };
-};
-
-key rndc_key {
-       secret "1234abcd8765";
-       algorithm @DEFAULT_HMAC@;
-};
-
-controls {
-       inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
-};
-
-zone "." { type primary; file "root.db"; };
-zone "signed" { type primary; file "signed.db.signed"; };
-zone "unsigned" { type primary; file "unsigned.db"; };
similarity index 64%
rename from bin/tests/system/filter-aaaa/ns2/named1.conf.in
rename to bin/tests/system/filter-aaaa/ns2/named.conf.j2
index c714c5429cb87a21df049d9f803b0948a3a783e5..9fee67291cafddbb70bc069dc58b2ebc0f66d1ff 100644 (file)
@@ -11,6 +11,9 @@
  * information regarding copyright ownership.
  */
 
+{% set filtertype = filtertype | default("aaaa") %}
+{% set family = family | default("v4") %}
+
 options {
        query-source address 10.53.0.2;
        notify-source 10.53.0.2;
@@ -25,10 +28,17 @@ options {
        minimal-responses no;
 };
 
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v4 yes;
-       filter-aaaa { 10.53.0.2; };
-};
+{% if family == "v6" %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v6 yes;
+                filter-@filtertype@ { fd92:7065:b8e:ffff::2; };
+        };
+{% else %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v4 yes;
+                filter-@filtertype@ { 10.53.0.2; };
+        };
+{% endif %}
 
 key rndc_key {
        secret "1234abcd8765";
diff --git a/bin/tests/system/filter-aaaa/ns2/named2.conf.in b/bin/tests/system/filter-aaaa/ns2/named2.conf.in
deleted file mode 100644 (file)
index fc77fc4..0000000
+++ /dev/null
@@ -1,44 +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.
- */
-
-options {
-       query-source address 10.53.0.2;
-       notify-source 10.53.0.2;
-       transfer-source 10.53.0.2;
-       port @PORT@;
-       pid-file "named.pid";
-       listen-on { 10.53.0.2; };
-       listen-on-v6 { fd92:7065:b8e:ffff::2; };
-       recursion yes;
-       dnssec-validation yes;
-       notify yes;
-       minimal-responses no;
-};
-
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v6 yes;
-       filter-aaaa { fd92:7065:b8e:ffff::2; };
-};
-
-key rndc_key {
-       secret "1234abcd8765";
-       algorithm @DEFAULT_HMAC@;
-};
-
-controls {
-       inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
-};
-
-zone "." { type hint; file "hints"; };
-
-include "trusted.conf";
similarity index 63%
rename from bin/tests/system/filter-aaaa/ns3/named2.conf.in
rename to bin/tests/system/filter-aaaa/ns3/named.conf.j2
index 5553e05b4dd6dc079da31ca24cbbb6d08cb06426..d89f96df2c546493535c93f54897a1c292d777bc 100644 (file)
@@ -11,6 +11,9 @@
  * information regarding copyright ownership.
  */
 
+{% set filtertype = filtertype | default("aaaa") %}
+{% set family = family | default("v4") %}
+
 options {
        query-source address 10.53.0.3;
        notify-source 10.53.0.3;
@@ -25,10 +28,17 @@ options {
        minimal-responses no;
 };
 
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v6 break-dnssec;
-       filter-aaaa { fd92:7065:b8e:ffff::3; };
-};
+{% if family == "v6" %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v6 break-dnssec;
+                filter-@filtertype@ { fd92:7065:b8e:ffff::3; };
+        };
+{% else %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v4 break-dnssec;
+                filter-@filtertype@ { 10.53.0.3; };
+        };
+{% endif %}
 
 key rndc_key {
        secret "1234abcd8765";
diff --git a/bin/tests/system/filter-aaaa/ns3/named1.conf.in b/bin/tests/system/filter-aaaa/ns3/named1.conf.in
deleted file mode 100644 (file)
index b11eea3..0000000
+++ /dev/null
@@ -1,44 +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.
- */
-
-options {
-       query-source address 10.53.0.3;
-       notify-source 10.53.0.3;
-       transfer-source 10.53.0.3;
-       port @PORT@;
-       pid-file "named.pid";
-       listen-on { 10.53.0.3; };
-       listen-on-v6 { fd92:7065:b8e:ffff::3; };
-       recursion yes;
-       dnssec-validation yes;
-       notify yes;
-       minimal-responses no;
-};
-
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v4 break-dnssec;
-       filter-aaaa { 10.53.0.3; };
-};
-
-key rndc_key {
-       secret "1234abcd8765";
-       algorithm @DEFAULT_HMAC@;
-};
-
-controls {
-       inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
-};
-
-zone "." { type hint; file "hints"; };
-
-include "trusted.conf";
similarity index 65%
rename from bin/tests/system/filter-aaaa/ns4/named1.conf.in
rename to bin/tests/system/filter-aaaa/ns4/named.conf.j2
index 6d3a9cceee51f3dea54ae0ec2cca6a06abbcf8b3..4246092923cf19678eabb8a17a9fd875fb603e95 100644 (file)
@@ -11,6 +11,9 @@
  * information regarding copyright ownership.
  */
 
+{% set filtertype = filtertype | default("aaaa") %}
+{% set family = family | default("v4") %}
+
 options {
        query-source address 10.53.0.4;
        notify-source 10.53.0.4;
@@ -25,10 +28,17 @@ options {
        minimal-responses no;
 };
 
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v4 break-dnssec;
-       filter-aaaa { 10.53.0.4; };
-};
+{% if family == "v6" %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v6 break-dnssec;
+                filter-@filtertype@ { fd92:7065:b8e:ffff::4; };
+        };
+{% else %}
+        plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+                filter-@filtertype@-on-v4 break-dnssec;
+                filter-@filtertype@ { 10.53.0.4; };
+        };
+{% endif %}
 
 key rndc_key {
        secret "1234abcd8765";
diff --git a/bin/tests/system/filter-aaaa/ns4/named2.conf.in b/bin/tests/system/filter-aaaa/ns4/named2.conf.in
deleted file mode 100644 (file)
index 91e3853..0000000
+++ /dev/null
@@ -1,44 +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.
- */
-
-options {
-       query-source address 10.53.0.4;
-       notify-source 10.53.0.4;
-       transfer-source 10.53.0.4;
-       port @PORT@;
-       pid-file "named.pid";
-       listen-on { 10.53.0.4; };
-       listen-on-v6 { fd92:7065:b8e:ffff::4; };
-       recursion no;
-       dnssec-validation no;
-       notify yes;
-       minimal-responses no;
-};
-
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v6 break-dnssec;
-       filter-aaaa { fd92:7065:b8e:ffff::4; };
-};
-
-key rndc_key {
-       secret "1234abcd8765";
-       algorithm @DEFAULT_HMAC@;
-};
-
-controls {
-       inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
-};
-
-zone "." { type primary; file "root.db"; };
-zone "signed" { type primary; file "signed.db.signed"; };
-zone "unsigned" { type primary; file "unsigned.db"; };
similarity index 84%
rename from bin/tests/system/filter-aaaa/ns5/named.conf.in
rename to bin/tests/system/filter-aaaa/ns5/named.conf.j2
index 58acd797eae55b6afa7d8874c29d7185a487af52..ae72eb33c4ebe48c7206d9e6fa2bcf02a3c5edd3 100644 (file)
@@ -11,6 +11,8 @@
  * information regarding copyright ownership.
  */
 
+{% set filtertype = filtertype | default("aaaa") %}
+
 options {
        query-source address 10.53.0.5;
        notify-source 10.53.0.5;
@@ -30,9 +32,9 @@ options {
        minimal-responses no;
 };
 
-plugin query "@TOP_BUILDDIR@/filter-aaaa.@DYLIB@" {
-       filter-aaaa-on-v4 break-dnssec;
-       filter-aaaa { any; };
+plugin query "@TOP_BUILDDIR@/filter-@filtertype@.@DYLIB@" {
+       filter-@filtertype@-on-v4 break-dnssec;
+       filter-@filtertype@ { any; };
 };
 
 key rndc_key {
index 3e151f04d4fb74565598b645c6037ec0e426ea34..e60dc57fd3ef3fe5eb4a719bc3fc8ed2242ffe51 100644 (file)
 
 . ../conf.sh
 
-copy_setports ns1/named1.conf.in ns1/named.conf
-copy_setports ns2/named1.conf.in ns2/named.conf
-copy_setports ns3/named1.conf.in ns3/named.conf
-copy_setports ns4/named1.conf.in ns4/named.conf
-copy_setports ns5/named.conf.in ns5/named.conf
-
-copy_setports conf/good1.conf.in conf/good1.conf
-copy_setports conf/good2.conf.in conf/good2.conf
-copy_setports conf/good3.conf.in conf/good3.conf
-copy_setports conf/good4.conf.in conf/good4.conf
-copy_setports conf/good5.conf.in conf/good5.conf
-
-copy_setports conf/bad1.conf.in conf/bad1.conf
-copy_setports conf/bad2.conf.in conf/bad2.conf
-copy_setports conf/bad3.conf.in conf/bad3.conf
-copy_setports conf/bad4.conf.in conf/bad4.conf
-copy_setports conf/bad5.conf.in conf/bad5.conf
-
 (cd ns1 && $SHELL -e sign.sh)
 (cd ns4 && $SHELL -e sign.sh)
diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh
deleted file mode 100644 (file)
index e6cca52..0000000
+++ /dev/null
@@ -1,1405 +0,0 @@
-#!/bin/sh
-
-# 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.
-
-set -e
-
-. ../conf.sh
-
-status=0
-n=0
-
-rm -f dig.out.*
-
-DIGOPTS="+tcp +noadd +nosea +nostat +nocmd -p ${PORT}"
-RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
-
-for conf in conf/good*.conf; do
-  n=$((n + 1))
-  echo_i "checking that $conf is accepted ($n)"
-  ret=0
-  $CHECKCONF "$conf" || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-done
-
-for conf in conf/bad*.conf; do
-  n=$((n + 1))
-  echo_i "checking that $conf is rejected ($n)"
-  ret=0
-  $CHECKCONF "$conf" >/dev/null && ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-done
-
-#
-# Authoritative tests against:
-#      filter-aaaa-on-v4 yes;
-#      filter-aaaa { 10.53.0.1; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "AUTHORITY: 1," dig.out.ns1.test$n >/dev/null || ret=1
-grep ::2 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "AUTHORITY: 1," dig.out.ns1.test$n >/dev/null || ret=1
-grep ::5 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "AUTHORITY: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "AUTHORITY: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "AUTHORITY: 2," dig.out.ns1.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "AUTHORITY: 0," dig.out.ns1.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "AUTHORITY: 1," dig.out.ns1.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns1.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns1.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns1.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns1.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, signed, qtype=ANY and DO is set ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "AUTHORITY: 2," dig.out.ns1.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns1.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns1.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.2 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "AUTHORITY: 1," dig.out.ns1.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns1.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv6 ($n)"
-if testsock6 fd92:7065:b8e:ffff::1; then
-  ret=0
-  $DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-  grep 2001:db8::6 dig.out.ns1.test$n >/dev/null || ret=1
-  grep "AUTHORITY: 1," dig.out.ns1.test$n >/dev/null || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS ($n)"
-ret=0
-$DIG $DIGOPTS +add ns unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep AAAA dig.out.ns1.test$n >/dev/null 2>&1 && ret=1
-grep "ANSWER: 1," dig.out.ns1.test$n >/dev/null || ret=1
-grep "ADDITIONAL: 2" dig.out.ns1.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns1.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, signed ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns1.test$n >/dev/null 2>&1 || ret=1
-grep "AUTHORITY: 2," dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv6 ($n)"
-if testsock6 fd92:7065:b8e:ffff::1; then
-  ret=0
-  $DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-  grep "^mx.unsigned.*AAAA" dig.out.ns1.test$n >/dev/null 2>&1 || ret=1
-  grep "AUTHORITY: 1," dig.out.ns1.test$n >/dev/null || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-#
-# Authoritative tests against:
-#      filter-aaaa-on-v4 break-dnssec;
-#      filter-aaaa { 10.53.0.4; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "AUTHORITY: 1," dig.out.ns4.test$n >/dev/null || ret=1
-grep ::2 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "AUTHORITY: 1," dig.out.ns4.test$n >/dev/null || ret=1
-grep ::5 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "AUTHORITY: 0," dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed and DO set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns4.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns4.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns4.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns4.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.2 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns4.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv6 with break-dnssec ($n)"
-if testsock6 fd92:7065:b8e:ffff::4; then
-  ret=0
-  $DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-  grep 2001:db8::6 dig.out.ns4.test$n >/dev/null || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add ns unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep AAAA dig.out.ns4.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns4.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns4.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns4.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv6, with break-dnssec ($n)"
-if testsock6 fd92:7065:b8e:ffff::4; then
-  ret=0
-  $DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-  grep "^mx.unsigned.*AAAA" dig.out.ns4.test$n >/dev/null 2>&1 || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-#
-# Recursive tests against:
-#      filter-aaaa-on-v4 yes;
-#      filter-aaaa { 10.53.0.2; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::2 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep ::5 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.1 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns2.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns2.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns2.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns2.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, signed, qtype=ANY and DO is set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns2.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns2.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl, recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.1 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns2.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv6, recursive ($n)"
-if testsock6 fd92:7065:b8e:ffff::2; then
-  ret=0
-  $DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-  grep 2001:db8::6 dig.out.ns2.test$n >/dev/null || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS ($n)"
-ret=0
-$DIG $DIGOPTS +add ns unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep AAAA dig.out.ns2.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns2.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, recursive ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, signed, recursive ($n)"
-ret=0
-# we need to prime the cache with addresses for the MX, since additional
-# section data won't be included unless it's validated, and that doesn't
-# necessarily happen otherwise.
-$DIG $DIGOPTS +dnssec mx.signed @10.53.0.2 >/dev/null
-$DIG $DIGOPTS +dnssec mx.signed aaaa @10.53.0.2 >/dev/null
-$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns2.test$n >/dev/null 2>&1 || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, recursive, over IPv6 ($n)"
-if testsock6 fd92:7065:b8e:ffff::2; then
-  ret=0
-  $DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-  grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n >/dev/null 2>&1 || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-#
-# Recursive tests against:
-#      filter-aaaa-on-v4 break-dnssec;
-#      filter-aaaa { 10.53.0.3; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null || ret=1
-grep ::2 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep ::5 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed and DO set, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.1 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns3.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns3.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns3.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns3.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b 10.53.0.1 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns3.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv6, recursive with break-dnssec ($n)"
-if testsock6 fd92:7065:b8e:ffff::3; then
-  ret=0
-  $DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-  grep 2001:db8::6 dig.out.ns3.test$n >/dev/null || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add ns unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep AAAA dig.out.ns3.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns3.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns3.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns3.test$n >/dev/null 2>&1 && ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv6, recursive with break-dnssec ($n)"
-if testsock6 fd92:7065:b8e:ffff::3; then
-  ret=0
-  $DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-  grep "^mx.unsigned.*AAAA" dig.out.ns3.test$n >/dev/null 2>&1 || ret=1
-  if [ $ret != 0 ]; then echo_i "failed"; fi
-  status=$((status + ret))
-else
-  echo_i "skipped."
-fi
-
-if ! testsock6 fd92:7065:b8e:ffff::1; then
-  echo_i "IPv6 address not configured; skipping IPv6 query tests"
-  echo_i "exit status: $status"
-  exit $status
-fi
-
-# Reconfiguring for IPv6 tests
-echo_i "reconfiguring servers"
-copy_setports ns1/named2.conf.in ns1/named.conf
-rndc_reconfig ns1 10.53.0.1
-copy_setports ns2/named2.conf.in ns2/named.conf
-rndc_reconfig ns2 10.53.0.2
-copy_setports ns3/named2.conf.in ns3/named.conf
-rndc_reconfig ns3 10.53.0.3
-copy_setports ns4/named2.conf.in ns4/named.conf
-rndc_reconfig ns4 10.53.0.4
-
-# BEGIN IPv6 TESTS
-
-#
-# Authoritative tests against:
-#      filter-aaaa-on-v6 yes;
-#      filter-aaaa { fd92:7065:b8e:ffff::1; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep ::2 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep ::5 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep ::3 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns1.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns1.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns1.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns1.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns1.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, signed, qtype=ANY and DO is set ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns1.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns1.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns1.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv4 ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep 2001:db8::6 dig.out.ns1.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec ns unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep AAAA dig.out.ns1.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns1.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns1.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, signed ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::1 >dig.out.ns1.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns1.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv4 ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.1 @10.53.0.1 >dig.out.ns1.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns1.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-#
-# Authoritative tests against:
-#      filter-aaaa-on-v6 break-dnssec;
-#      filter-aaaa { fd92:7065:b8e:ffff::4; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep ::2 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep ::5 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed and DO set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns4.test$n >/dev/null || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns4.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns4.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns4.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns4.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns4.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "status: NOERROR" dig.out.ns4.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns4.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv4 with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep 2001:db8::6 dig.out.ns4.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec ns unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep AAAA dig.out.ns4.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns4.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns4.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::4 @fd92:7065:b8e:ffff::4 >dig.out.ns4.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns4.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv4, with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.4 @10.53.0.4 >dig.out.ns4.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns4.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-#
-# Recursive tests against:
-#      filter-aaaa-on-v6 yes;
-#      filter-aaaa { fd92:7065:b8e:ffff::2; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::2 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep ::5 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns2.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns2.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns2.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns2.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, signed, qtype=ANY and DO is set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set, recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns2.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns2.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl, recursive ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "status: NOERROR" dig.out.ns2.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns2.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv4, recursive ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep 2001:db8::6 dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec ns unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep AAAA dig.out.ns2.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns2.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, signed ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 >dig.out.ns2.test$n || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns2.test$n >/dev/null 2>&1 || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns2.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv4 ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.2 @10.53.0.2 >dig.out.ns2.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-#
-# Recursive tests against:
-#      filter-aaaa-on-v6 yes;
-#      filter-aaaa { fd92:7065:b8e:ffff::3; };
-#
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null || ret=1
-grep ::2 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when only AAAA record exists, unsigned, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep ::5 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, signed and DO set, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records exist, unsigned and DO set, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "ANSWER: 0" dig.out.ns3.test$n >/dev/null || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null && ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A records exist and query source does not match acl, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns3.test$n >/dev/null || ret=1
-grep "::3" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned and qtype=ANY with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns3.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, signed, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.3" dig.out.ns3.test$n >/dev/null || ret=1
-grep ::3 dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that A and not AAAA is returned when both AAAA and A records exist, unsigned, qtype=ANY and DO is set with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep "1.0.0.6" dig.out.ns3.test$n >/dev/null || ret=1
-grep "::6" dig.out.ns3.test$n >/dev/null && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that both A and AAAA are returned when both AAAA and A records exist, qtype=ANY and query source does not match acl, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS any dual.unsigned -b fd92:7065:b8e:ffff::1 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "status: NOERROR" dig.out.ns3.test$n >/dev/null || ret=1
-grep 1.0.0.6 dig.out.ns3.test$n >/dev/null || ret=1
-grep ::6 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is returned when both AAAA and A record exists, unsigned over IPv4, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep 2001:db8::6 dig.out.ns3.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=NS, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec ns unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep AAAA dig.out.ns3.test$n >/dev/null 2>&1 && ret=1
-grep "ADDITIONAL: 2" dig.out.ns3.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns3.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 >dig.out.ns3.test$n || ret=1
-grep "flags:.*ad.*QUERY" dig.out.ns3.test$n >/dev/null || ret=1
-grep "^mx.signed.*AAAA" dig.out.ns3.test$n >/dev/null 2>&1 && ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv4, recursive with break-dnssec ($n)"
-ret=0
-$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.3 @10.53.0.3 >dig.out.ns3.test$n || ret=1
-grep "^mx.unsigned.*AAAA" dig.out.ns3.test$n >/dev/null 2>&1 || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-# We don't check for the AAAA record here as configuration in ns5 does
-# not make sense.  The AAAA record is wanted by filter-aaaa but discarded
-# by the dns64 configuration. We just want to ensure the server stays
-# running.
-n=$((n + 1))
-echo_i "checking filter-aaaa with dns64 ($n)"
-ret=0
-$DIG $DIGOPTS aaaa aaaa-only.unsigned @10.53.0.5 >dig.out.ns5.test$n || ret=1
-grep "status: NOERROR" dig.out.ns5.test$n >/dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=$((status + ret))
-
-echo_i "exit status: $status"
-[ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/filter-aaaa/tests_filter_aaaa.py b/bin/tests/system/filter-aaaa/tests_filter_aaaa.py
new file mode 100644 (file)
index 0000000..920a887
--- /dev/null
@@ -0,0 +1,1401 @@
+#!/bin/sh
+
+# 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 glob
+import os
+import subprocess
+
+from dns import message, rdatatype
+
+import pytest
+
+import isctest
+import isctest.mark
+
+
+pytestmark = pytest.mark.extra_artifacts(
+    [
+        "conf/*.conf",
+        "ns*/trusted.conf",
+        "ns*/*.signed",
+        "ns*/K*",
+        "ns*/dsset-*",
+        "ns*/signer.err",
+    ]
+)
+
+
+# helper functions
+def reset_server(server, family, ftype, servers, templates):
+    templates.render(f"{server}/named.conf",
+            {"family": family, "filtertype": ftype})
+    servers[server].reconfigure(log=False)
+
+
+filter_family = "v4"
+filter_type = "aaaa"
+def reset_servers(family, ftype, servers, templates):
+    reset_server("ns1", family, ftype, servers, templates)
+    reset_server("ns2", family, ftype, servers, templates)
+    reset_server("ns3", family, ftype, servers, templates)
+    reset_server("ns4", family, ftype, servers, templates)
+    filter_family = family
+
+
+# run the checkconf tests
+def test_checkconf():
+    for filename in glob.glob("conf/good*.conf"):
+        isctest.run.cmd([os.environ["CHECKCONF"], filename])
+    for filename in glob.glob("conf/bad*.conf"):
+        with pytest.raises(subprocess.CalledProcessError):
+            isctest.run.cmd([os.environ["CHECKCONF"], filename])
+
+
+# These tests are against an authoritative server configured with:
+## filter-aaaa-on-v4 yes;
+## filter-aaaa { 10.53.0.1; };
+def test_auth_filter_aaaa_on_v4(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned when both AAAA and A exist, signed, DO=1
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa = res.answer[0]
+    assert "2001:db8::3" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=1
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS, unsigned
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX, unsigned
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is included in additional section, qtype=MX, signed
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.1", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+@isctest.mark.with_ipv6
+def test_auth_filter_aaaa_on_v4_via_v6(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against an authoritative server configured with:
+## filter-aaaa-on-v4 break-dnssec;
+## filter-aaaa { 10.53.0.4; };
+def test_auth_break_dnssec_filter_aaaa_on_v4(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed,
+    # with break-dnssec
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned,
+    # with break-dnssec
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0, with break-dnssec
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0, with break-dnssec
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned when both AAAA and A exist, signed, DO=1,
+    # with break-dnssec
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, with break-dnssec
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=1, with break-dnssec
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0, with break-dnssec
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS,
+    # unsigned, with break-dnssec
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # unsigned, with break-dnssec
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # signed, with break-dnssec
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.4", source="10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+@isctest.mark.with_ipv6
+def test_auth_break_dnssec_filter_aaaa_on_v4_via_v6(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6, with break-dnssec
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against a recursive server configured with:
+## filter-aaaa-on-v4 yes;
+## filter-aaaa { 10.53.0.2; };
+def test_recursive_filter_aaaa_on_v4(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed,
+    # recursive
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned,
+    # recursive
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0, recursive
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0, recursive
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned when both AAAA and A exist, signed, DO=1,
+    # recursive
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa = res.answer[0]
+    assert "2001:db8::3" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, recursive
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noadflag(res)
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, recursive
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=1, recursive
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0, recursive
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1, recursive
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL, recursive
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS,
+    # unsigned, recursive
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # unsigned, recursive
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # (we need to prime the cache first with the MX addresses, since
+    # additional section data isn't included unless it's already validated.)
+    msg = isctest.query.create("mx.signed", "a")
+    isctest.query.tcp(msg, "10.53.0.2")
+    msg = isctest.query.create("mx.signed", "aaaa")
+    isctest.query.tcp(msg, "10.53.0.2")
+
+    # check that AAAA is included in additional section, qtype=MX, signed,
+    # recursive
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.2", source="10.53.0.2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+@isctest.mark.with_ipv6
+def test_recursive_filter_aaaa_on_v4_via_v6(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against a recursive server configured with:
+## filter-aaaa-on-v4 break-dnssec;
+## filter-aaaa { 10.53.0.3; };
+def test_recursive_break_dnssec_filter_aaaa_on_v4(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed,
+    # recursive, with break-dnssec
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned,
+    # recursive, with break-dnssec
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, recursive, with break-dnssec
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, recursive, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noadflag(res)
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, recursive, with break-dnssec
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1, recursive, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL, recursive, with
+    # break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS,
+    # unsigned, recursive, with break-dnssec
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # unsigned, recursive, with break-dnssec
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX, signed,
+    # recursive, with break-dnssec
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.3", source="10.53.0.3")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+@isctest.mark.with_ipv6
+def test_recursive_break_dnssec_filter_aaaa_on_v4_via_v6(servers, templates):
+    if filter_family != "v4" or filter_type != "aaaa":
+        reset_servers("v4", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against an authoritative server configured with:
+## filter-aaaa-on-v6 yes;
+## filter-aaaa { fd92:7065:b8e:ffff::1; };
+@isctest.mark.with_ipv6
+def test_auth_filter_aaaa_on_v6(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned when both AAAA and A exist, signed, DO=1
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa = res.answer[0]
+    assert "2001:db8::3" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=1
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS, unsigned
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX, unsigned
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is included in additional section, qtype=MX, signed
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::1",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+def test_auth_filter_aaaa_on_v6_via_v4(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.1")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against an authoritative server configured with:
+## filter-aaaa-on-v6 break-dnssec;
+## filter-aaaa { fd92:7065:b8e:ffff::4; };
+@isctest.mark.with_ipv6
+def test_auth_break_dnssec_filter_aaaa_on_v6(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed,
+    # with break-dnssec
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned,
+    # with break-dnssec
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0, with break-dnssec
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0, with break-dnssec
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned when both AAAA and A exist, signed, DO=1,
+    # with break-dnssec
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, with break-dnssec
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=1, with break-dnssec
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0, with break-dnssec
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS,
+    # unsigned, with break-dnssec
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # unsigned, with break-dnssec
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # signed, with break-dnssec
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::4",
+            source="fd92:7065:b8e:ffff::4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+def test_auth_break_dnssec_filter_aaaa_on_v6_via_v4(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6, with break-dnssec
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against a recursive server configured with:
+## filter-aaaa-on-v6 yes;
+## filter-aaaa { fd92:7065:b8e:ffff::2; };
+@isctest.mark.with_ipv6
+def test_recursive_filter_aaaa_on_v6(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed,
+    # recursive
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned,
+    # recursive
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0, recursive
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0, recursive
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned when both AAAA and A exist, signed, DO=1,
+    # recursive
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    aaaa = res.answer[0]
+    assert "2001:db8::3" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, recursive
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noadflag(res)
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, recursive
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=1, recursive
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0, recursive
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1, recursive
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL, recursive
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS,
+    # unsigned, recursive
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # unsigned, recursive
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # (we need to prime the cache first with the MX addresses, since
+    # additional section data isn't included unless it's already validated.)
+    msg = isctest.query.create("mx.signed", "a")
+    isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2")
+    msg = isctest.query.create("mx.signed", "aaaa")
+    isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2")
+
+    # check that AAAA is included in additional section, qtype=MX, signed,
+    # recursive
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::2",
+            source="fd92:7065:b8e:ffff::2")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+def test_recursive_filter_aaaa_on_v6_via_v4(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+# These tests are against a recursive server configured with:
+## filter-aaaa-on-v6 break-dnssec;
+## filter-aaaa { fd92:7065:b8e:ffff::3; };
+@isctest.mark.with_ipv6
+def test_recursive_break_dnssec_filter_aaaa_on_v6(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when only AAAA record exists, signed,
+    # recursive, with break-dnssec
+    msg = isctest.query.create("aaaa-only.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+    aaaa, _ = res.answer
+    assert "2001:db8::2" in str(aaaa[0])
+
+    # check that AAAA is returned when only AAAA record exists, unsigned,
+    # recursive, with break-dnssec
+    msg = isctest.query.create("aaaa-only.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    aaaa = res.answer[0]
+    assert "2001:db8::5" in str(aaaa[0])
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # signed, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.signed", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.unsigned", "aaaa") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, recursive, with break-dnssec
+    msg = isctest.query.create("dual.signed", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.empty_answer(res)
+
+    # check that NODATA/NOERROR is returned when both AAAA and A exist,
+    # unsigned, DO=1, recursive, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noadflag(res)
+    isctest.check.noerror(res)
+    isctest.check.empty_answer(res)
+
+    # check that AAAA is returned if both AAAA and A exist and the query
+    # source doesn't match the ACL, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.signed", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # signed, qtype=ANY, DO=0, recursive, with break-dnssec
+    msg = isctest.query.create("dual.signed", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.noadflag(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.3" in r for r in records)
+    assert not any("2001:db8::3" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=0, recursive, with break-dnssec
+    msg = message.make_query("dual.unsigned", "any") # sends DO=0
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that A (and not AAAA) is returned if both AAAA and A exist,
+    # unsigned, qtype=ANY, DO=1, recursive, with break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert not any("2001:db8::6" in r for r in records)
+
+    # check that both A and AAAA are returned if both AAAA and A exist,
+    # signed, qtype=ANY, query source does not match ACL, recursive, with
+    # break-dnssec
+    msg = isctest.query.create("dual.unsigned", "any")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::1")
+    isctest.check.noerror(res)
+    records = sum([str(a).splitlines() for a in res.answer], [])
+    assert any("1.0.0.6" in r for r in records)
+    assert any("2001:db8::6" in r for r in records)
+
+    # check that AAAA is omitted from additional section, qtype=NS,
+    # unsigned, recursive, with break-dnssec
+    msg = isctest.query.create("unsigned", "ns")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 1)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX,
+    # unsigned, recursive, with break-dnssec
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.additional, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+    # check that AAAA is omitted from additional section, qtype=MX, signed,
+    # recursive, with break-dnssec
+    msg = isctest.query.create("signed", "mx")
+    res = isctest.query.tcp(msg, "fd92:7065:b8e:ffff::3",
+            source="fd92:7065:b8e:ffff::3")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 2)
+    assert not [a for a in res.additional if a.rdtype == rdatatype.AAAA]
+
+
+def test_recursive_break_dnssec_filter_aaaa_on_v6_via_v4(servers, templates):
+    if filter_family != "v6" or filter_type != "aaaa":
+        reset_servers("v6", "aaaa", servers, templates)
+
+    # check that AAAA is returned when both AAAA and A record exists,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("dual.unsigned", "aaaa")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    aaaa = res.answer[0]
+    assert "2001:db8::6" in str(aaaa[0])
+
+    # check that AAAA is included in additional section, qtype=MX,
+    # unsigned, over IPv6, recursive
+    msg = isctest.query.create("unsigned", "mx")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.rr_count_eq(res.authority, 1)
+    assert [a for a in res.additional if a.rdtype == rdatatype.AAAA]
diff --git a/bin/tests/system/filter-aaaa/tests_sh_filter_aaaa.py b/bin/tests/system/filter-aaaa/tests_sh_filter_aaaa.py
deleted file mode 100644 (file)
index 51c04dc..0000000
+++ /dev/null
@@ -1,32 +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.
-
-import pytest
-
-pytestmark = pytest.mark.extra_artifacts(
-    [
-        "conf/*.conf",
-        "dig.out.*",
-        "ns*/trusted.conf",
-        "ns1/*.signed",
-        "ns1/K*",
-        "ns1/dsset-*",
-        "ns1/signer.err",
-        "ns4/*.signed",
-        "ns4/K*",
-        "ns4/dsset-*",
-        "ns4/signer.err",
-    ]
-)
-
-
-def test_filter_aaaa(run_tests_sh):
-    run_tests_sh()
index 97a03d217af9b1279ec7234762d6a8cae3f4e46f..e1b97f8f840f38bdc3ea12d44d66355e92b722c6 100644 (file)
 
 import os
 import platform
+import socket
 import shutil
 import subprocess
 
 import pytest
 
-
 long_test = pytest.mark.skipif(
     not os.environ.get("CI_ENABLE_LONG_TESTS"), reason="CI_ENABLE_LONG_TESTS not set"
 )
@@ -91,3 +91,15 @@ softhsm2_environment = pytest.mark.skipif(
     ),
     reason="SOFTHSM2_CONF and SOFTHSM2_MODULE environmental variables must be set and pkcs11-tool and softhsm2-util tools present",
 )
+
+
+def have_ipv6():
+    sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+    try:
+        sock.bind(("fd92:7065:b8e:ffff::1", 0))
+    except OSError:
+        return False
+    return True
+
+
+with_ipv6 = pytest.mark.skipif(not have_ipv6(), reason="IPv6 not available")