2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 18:19:42 +00:00

- qname minimization:

- make qname-minimization option tristate {strict,relaxed,disabled}
 - go straight for the record if we hit NXDOMAIN in relaxed mode
 - go straight for the record after 3 labels without new delegation or 7 labels total

- use start of fetch (and not time of response) as 'now' time for querying cache for
  zonecut when following delegation.
This commit is contained in:
Witold Kręcicki 2018-05-11 12:27:56 +02:00
parent 0698158eb0
commit dd7bb617be
16 changed files with 612 additions and 76 deletions

View File

@ -185,8 +185,7 @@ options {\n\
provide-ixfr true;\n\ provide-ixfr true;\n\
query-source address *;\n\ query-source address *;\n\
query-source-v6 address *;\n\ query-source-v6 address *;\n\
qname-minimization no;\n\ qname-minimization relaxed;\n\
qname-minimization-strict no;\n\
recursion true;\n\ recursion true;\n\
request-expire true;\n\ request-expire true;\n\
request-ixfr true;\n\ request-ixfr true;\n\

View File

@ -4642,12 +4642,18 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
obj = NULL; obj = NULL;
result = named_config_get(maps, "qname-minimization", &obj); result = named_config_get(maps, "qname-minimization", &obj);
INSIST(result == ISC_R_SUCCESS); INSIST(result == ISC_R_SUCCESS);
view->qminimization = cfg_obj_asboolean(obj); const char * qminmode = cfg_obj_asstring(obj);
INSIST(qminmode != NULL);
obj = NULL; if (!strcmp(qminmode, "strict")) {
result = named_config_get(maps, "qname-minimization-strict", &obj); view->qminimization = ISC_TRUE;
INSIST(result == ISC_R_SUCCESS); view->qmin_strict = ISC_TRUE;
view->qmin_strict = cfg_obj_asboolean(obj); } else if (!strcmp(qminmode, "relaxed")) {
view->qminimization = ISC_TRUE;
view->qmin_strict = ISC_FALSE;
} else {
view->qminimization = ISC_FALSE;
view->qmin_strict = ISC_FALSE;
}
obj = NULL; obj = NULL;
result = named_config_get(maps, "auth-nxdomain", &obj); result = named_config_get(maps, "auth-nxdomain", &obj);

View File

@ -35,7 +35,9 @@ def logquery(type, qname):
# Respond to a DNS query. # Respond to a DNS query.
# For good. it serves: # For good. it serves:
# ns2.good. IN A 10.53.0.2 # ns2.good. IN A 10.53.0.2
# icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.1 # zoop.boing.good. NS ns3.good.
# ns3.good. IN A 10.53.0.3
# too.many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.good. A 192.0.2.2
# it responds properly (with NODATA empty response) to non-empty terminals # it responds properly (with NODATA empty response) to non-empty terminals
# #
# For slow. it works the same as for good., but each response is delayed by 400 miliseconds # For slow. it works the same as for good., but each response is delayed by 400 miliseconds
@ -111,20 +113,33 @@ def create_response(msg):
return r return r
# Good/bad differs only in how we treat non-empty terminals # Good/bad differs only in how we treat non-empty terminals
if lqname == "icky.icky.icky.ptang.zoop.boing." and rrtype == A: if lqname.endswith("zoop.boing."):
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.1")) r.authority.append(dns.rrset.from_text("zoop.boing." + suffix, 1, IN, NS, "ns3." + suffix))
elif lqname == "many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.2"))
elif lqname == "" and rrtype == NS: elif lqname == "" and rrtype == NS:
r.answer.append(dns.rrset.from_text(suffix, 1, IN, NS, "ns2." + suffix)) r.answer.append(dns.rrset.from_text(suffix, 1, IN, NS, "ns2." + suffix))
elif lqname == "ns2." and rrtype == A: elif lqname == "ns2." and rrtype == A:
r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, A, "10.53.0.2")) r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, A, "10.53.0.2"))
elif lqname == "ns2." and rrtype == AAAA: elif lqname == "ns2." and rrtype == AAAA:
r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::2")) r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::2"))
elif lqname == "ns3." and rrtype == A:
r.answer.append(dns.rrset.from_text("ns3."+suffix, 1, IN, A, "10.53.0.3"))
elif lqname == "ns3." and rrtype == AAAA:
r.answer.append(dns.rrset.from_text("ns3."+suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::3"))
elif lqname == "a.bit.longer.ns.name." and rrtype == A:
r.answer.append(dns.rrset.from_text("a.bit.longer.ns.name."+suffix, 1, IN, A, "10.53.0.4"))
elif lqname == "a.bit.longer.ns.name." and rrtype == AAAA:
r.answer.append(dns.rrset.from_text("a.bit.longer.ns.name."+suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::4"))
else: else:
r.authority.append(dns.rrset.from_text(suffix, 1, IN, SOA, "ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1")) r.authority.append(dns.rrset.from_text(suffix, 1, IN, SOA, "ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1"))
if bad or not "icky.icky.icky.ptang.zoop.boing.".endswith(lqname): if bad or not \
("icky.icky.icky.ptang.zoop.boing.".endswith(lqname) or \
"many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.".endswith(lqname) or \
"a.bit.longer.ns.name.".endswith(lqname)):
r.set_rcode(NXDOMAIN) r.set_rcode(NXDOMAIN)
if slow: if slow:
time.sleep(0.4) time.sleep(0.2)
return r return r

View File

@ -0,0 +1,175 @@
############################################################################
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
############################################################################
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
import dns, dns.message, dns.query
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
############################################################################
# Respond to a DNS query.
# For good. it serves:
# zoop.boing.good. NS ns3.good.
# icky.ptang.zoop.boing.good. NS a.bit.longer.ns.name.good.
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 miliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split('.')
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
bad = False
slow = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
if lqname.endswith("bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif lqname.endswith("good."):
suffix = "good."
lqname = lqname[:-5]
elif lqname.endswith("slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
else:
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
if lqname == "zoop.boing." and rrtype == NS:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, NS, "ns3."+suffix))
elif lqname.endswith("icky.ptang.zoop.boing."):
r.authority.append(dns.rrset.from_text("icky.ptang.zoop.boing." + suffix, 1, IN, NS, "a.bit.longer.ns.name." + suffix))
elif "icky.ptang.zoop.boing.".endswith(lqname):
r.authority.append(dns.rrset.from_text("zoop.boing." + suffix, 1, IN, SOA, "ns3." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1"))
if bad:
r.set_rcode(NXDOMAIN)
elif "zoop.boing.".endswith(lqname):
r.authority.append(dns.rrset.from_text("zoop.boing." + suffix, 1, IN, SOA, "ns3." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1"))
r.set_rcode(NXDOMAIN)
else:
r.set_rcode(REFUSED)
if slow:
time.sleep(0.4)
return r
def sigterm(signum, frame):
print ("Shutting down now...")
os.remove('ans.pid')
running = False
sys.exit(0)
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.3"
ip6 = "fd92:7065:b8e:ffff::3"
try: port=int(os.environ['PORT'])
except: port=5300
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
f = open('ans.pid', 'w')
pid = os.getpid()
print (pid, file=f)
f.close()
running = True
print ("Listening on %s port %d" % (ip4, port))
if havev6:
print ("Listening on %s port %d" % (ip6, port))
print ("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print ("Query received on %s" %
(ip4 if s == query4_socket else ip6), end=" ")
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break

View File

@ -0,0 +1,175 @@
############################################################################
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
############################################################################
from __future__ import print_function
import os
import sys
import signal
import socket
import select
from datetime import datetime, timedelta
import time
import functools
import dns, dns.message, dns.query
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
from dns.name import *
# Log query to file
def logquery(type, qname):
with open("qlog", "a") as f:
f.write("%s %s\n", type, qname)
############################################################################
# Respond to a DNS query.
# For good. it serves:
# icky.ptang.zoop.boing.good. NS a.bit.longer.ns.name.
# icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.1
# more.icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.2
# it responds properly (with NODATA empty response) to non-empty terminals
#
# For slow. it works the same as for good., but each response is delayed by 400 miliseconds
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
qname = m.question[0].name.to_text()
lqname = qname.lower()
labels = lqname.split('.')
# get qtype
rrtype = m.question[0].rdtype
typename = dns.rdatatype.to_text(rrtype)
bad = False
slow = False
# log this query
with open("query.log", "a") as f:
f.write("%s %s\n" % (typename, lqname))
print("%s %s" % (typename, lqname), end=" ")
r = dns.message.make_response(m)
r.set_rcode(NOERROR)
if lqname.endswith("bad."):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif lqname.endswith("good."):
suffix = "good."
lqname = lqname[:-5]
elif lqname.endswith("slow."):
slow = True
suffix = "slow."
lqname = lqname[:-5]
else:
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
if lqname == "icky.icky.icky.ptang.zoop.boing." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.1"))
elif lqname == "more.icky.icky.icky.ptang.zoop.boing." and rrtype == A:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, A, "192.0.2.2"))
elif lqname == "icky.ptang.zoop.boing." and rrtype == NS:
r.answer.append(dns.rrset.from_text(lqname + suffix, 1, IN, NS, "a.bit.longer.ns.name."+suffix))
elif lqname.endswith("icky.ptang.zoop.boing."):
r.authority.append(dns.rrset.from_text("icky.ptang.zoop.boing." + suffix, 1, IN, SOA, "ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1"))
if bad or not "more.icky.icky.icky.ptang.zoop.boing.".endswith(lqname):
r.set_rcode(NXDOMAIN)
else:
r.set_rcode(REFUSED)
if slow:
time.sleep(0.4)
return r
def sigterm(signum, frame):
print ("Shutting down now...")
os.remove('ans.pid')
running = False
sys.exit(0)
############################################################################
# Main
#
# Set up responder and control channel, open the pid file, and start
# the main loop, listening for queries on the query channel or commands
# on the control channel and acting on them.
############################################################################
ip4 = "10.53.0.4"
ip6 = "fd92:7065:b8e:ffff::4"
try: port=int(os.environ['PORT'])
except: port=5300
query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
query4_socket.bind((ip4, port))
havev6 = True
try:
query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
query6_socket.bind((ip6, port))
except:
query6_socket.close()
havev6 = False
except:
havev6 = False
signal.signal(signal.SIGTERM, sigterm)
f = open('ans.pid', 'w')
pid = os.getpid()
print (pid, file=f)
f.close()
running = True
print ("Listening on %s port %d" % (ip4, port))
if havev6:
print ("Listening on %s port %d" % (ip6, port))
print ("Ctrl-c to quit")
if havev6:
input = [query4_socket, query6_socket]
else:
input = [query4_socket]
while running:
try:
inputready, outputready, exceptready = select.select(input, [], [])
except select.error as e:
break
except socket.error as e:
break
except KeyboardInterrupt:
break
for s in inputready:
if s == query4_socket or s == query6_socket:
print ("Query received on %s" %
(ip4 if s == query4_socket else ip6), end=" ")
# Handle incoming queries
msg = s.recvfrom(65535)
rsp = create_response(msg[0])
if rsp:
print(dns.rcode.to_text(rsp.rcode()))
s.sendto(rsp.to_wire(), msg[1])
else:
print("NO RESPONSE")
if not running:
break

View File

@ -14,4 +14,4 @@ rm -f */named.memstats
rm -f */named.run rm -f */named.run
rm -f dig.out.* rm -f dig.out.*
rm -f ns*/named.lock rm -f ns*/named.lock
rm -f ans2/query.log rm -f ans*/query.log

View File

@ -20,8 +20,7 @@ options {
listen-on { 10.53.0.5; }; listen-on { 10.53.0.5; };
listen-on-v6 { none; }; listen-on-v6 { none; };
recursion yes; recursion yes;
qname-minimization yes; qname-minimization disabled;
qname-minimization-strict no;
querylog yes; querylog yes;
resolver-query-timeout 30; resolver-query-timeout 30;
}; };

View File

@ -9,19 +9,18 @@
* information regarding copyright ownership. * information regarding copyright ownership.
*/ */
// NS3 // NS6
options { options {
query-source address 10.53.0.3; query-source address 10.53.0.6;
notify-source 10.53.0.3; notify-source 10.53.0.6;
transfer-source 10.53.0.3; transfer-source 10.53.0.6;
port @PORT@; port @PORT@;
pid-file "named.pid"; pid-file "named.pid";
listen-on { 10.53.0.3; }; listen-on { 10.53.0.6; };
listen-on-v6 { none; }; listen-on-v6 { none; };
recursion yes; recursion yes;
qname-minimization no; qname-minimization strict;
qname-minimization-strict no;
querylog yes; querylog yes;
resolver-query-timeout 30; resolver-query-timeout 30;
}; };
@ -32,7 +31,7 @@ key rndc_key {
}; };
controls { controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
}; };
zone "." { zone "." {

View File

@ -9,19 +9,18 @@
* information regarding copyright ownership. * information regarding copyright ownership.
*/ */
// NS4 // NS7
options { options {
query-source address 10.53.0.4; query-source address 10.53.0.7;
notify-source 10.53.0.4; notify-source 10.53.0.7;
transfer-source 10.53.0.4; transfer-source 10.53.0.7;
port @PORT@; port @PORT@;
pid-file "named.pid"; pid-file "named.pid";
listen-on { 10.53.0.4; }; listen-on { 10.53.0.7; };
listen-on-v6 { none; }; listen-on-v6 { none; };
recursion yes; recursion yes;
qname-minimization yes; qname-minimization relaxed;
qname-minimization-strict yes;
querylog yes; querylog yes;
resolver-query-timeout 30; resolver-query-timeout 30;
}; };
@ -32,7 +31,7 @@ key rndc_key {
}; };
controls { controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
}; };
zone "." { zone "." {

View File

@ -15,6 +15,6 @@ SYSTEMTESTTOP=..
$SHELL clean.sh $SHELL clean.sh
copy_setports ns1/named.conf.in ns1/named.conf copy_setports ns1/named.conf.in ns1/named.conf
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf
copy_setports ns5/named.conf.in ns5/named.conf copy_setports ns5/named.conf.in ns5/named.conf
copy_setports ns6/named.conf.in ns6/named.conf
copy_setports ns7/named.conf.in ns7/named.conf

View File

@ -14,7 +14,7 @@ SYSTEMTESTTOP=..
DIGOPTS="-p ${PORT}" DIGOPTS="-p ${PORT}"
RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
CLEANQL="rm -f ans2/query.log" CLEANQL="rm -f ans*/query.log"
status=0 status=0
n=0 n=0
@ -22,10 +22,19 @@ n=`expr $n + 1`
echo_i "query for .good is not minimized when qname-minimization is off ($n)" echo_i "query for .good is not minimized when qname-minimization is off ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.3 flush $RNDCCMD 10.53.0.5 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.good. @10.53.0.3 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.good. @10.53.0.5 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.good." | diff ans2/query.log - > /dev/null || ret=1 grep "icky.icky.icky.ptang.zoop.boing.good. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
A icky.icky.icky.ptang.zoop.boing.good.
A ns3.good.
AAAA ns3.good.
A a.bit.longer.ns.name.good.
AAAA a.bit.longer.ns.name.good.
__EOF
echo "A icky.icky.icky.ptang.zoop.boing.good." | diff ans3/query.log - > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.good." | diff ans4/query.log - > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@ -33,10 +42,19 @@ n=`expr $n + 1`
echo_i "query for .bad is not minimized when qname-minimization is off ($n)" echo_i "query for .bad is not minimized when qname-minimization is off ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.3 flush $RNDCCMD 10.53.0.5 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.3 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.5 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.bad." | diff ans2/query.log - > /dev/null || ret=1 grep "icky.icky.icky.ptang.zoop.boing.bad. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
A icky.icky.icky.ptang.zoop.boing.bad.
A ns3.bad.
AAAA ns3.bad.
A a.bit.longer.ns.name.bad.
AAAA a.bit.longer.ns.name.bad.
__EOF
echo "A icky.icky.icky.ptang.zoop.boing.bad." | diff ans3/query.log - > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.bad." | diff ans4/query.log - > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@ -44,10 +62,20 @@ n=`expr $n + 1`
echo_i "query for .slow is not minimized when qname-minimization is off ($n)" echo_i "query for .slow is not minimized when qname-minimization is off ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.3 flush $RNDCCMD 10.53.0.5 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.slow. @10.53.0.3 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.slow. @10.53.0.5 > dig.out.test$n
sleep 5
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.slow." | diff ans2/query.log - > /dev/null || ret=1 grep "icky.icky.icky.ptang.zoop.boing.slow. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
A icky.icky.icky.ptang.zoop.boing.slow.
A ns3.slow.
AAAA ns3.slow.
A a.bit.longer.ns.name.slow.
AAAA a.bit.longer.ns.name.slow.
__EOF
echo "A icky.icky.icky.ptang.zoop.boing.slow." | diff ans3/query.log - > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.slow." | diff ans4/query.log - > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@ -55,14 +83,35 @@ n=`expr $n + 1`
echo_i "query for .good is properly minimized when qname-minimization is on ($n)" echo_i "query for .good is properly minimized when qname-minimization is on ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.4 flush $RNDCCMD 10.53.0.6 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.good. @10.53.0.4 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.good. @10.53.0.6 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "icky.icky.icky.ptang.zoop.boing.good. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
# Duplicated NS queries are there because we're not creating
# a separate fetch when doing qname minimization - so two
# queries running for the same name but different RRTYPE
# (A and AAAA in this case) will create separate queries
# for NSes on the way. Those will be cached though, so it
# should not be a problem
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1 cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS boing.good. NS boing.good.
NS zoop.boing.good. NS zoop.boing.good.
A ns3.good.
AAAA ns3.good.
NS name.good.
NS name.good.
NS ns.name.good.
NS ns.name.good.
NS longer.ns.name.good.
NS longer.ns.name.good.
A a.bit.longer.ns.name.good.
AAAA a.bit.longer.ns.name.good.
__EOF
cat << __EOF | diff ans3/query.log - > /dev/null || ret=1
NS ptang.zoop.boing.good. NS ptang.zoop.boing.good.
NS icky.ptang.zoop.boing.good. NS icky.ptang.zoop.boing.good.
__EOF
cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.icky.ptang.zoop.boing.good. NS icky.icky.ptang.zoop.boing.good.
A icky.icky.icky.ptang.zoop.boing.good. A icky.icky.icky.ptang.zoop.boing.good.
__EOF __EOF
@ -70,31 +119,36 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
n=`expr $n + 1` n=`expr $n + 1`
echo_i "query for .bad fails when qname-minimization is on and in strict mode ($n)" echo_i "query for .bad fails when qname-minimization is in strict mode ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.4 flush $RNDCCMD 10.53.0.6 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.4 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.6 > dig.out.test$n
grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1
echo "NS boing.bad." | diff ans2/query.log - > /dev/null || ret=1 echo "NS boing.bad." | diff ans2/query.log - > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
n=`expr $n + 1` n=`expr $n + 1`
echo_i "query for .bad succeds when qname-minimization is on and not in strict mode ($n)" echo_i "query for .bad succeds when qname-minimization is in relaxed mode ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.5 flush $RNDCCMD 10.53.0.7 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.5 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.7 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "icky.icky.icky.ptang.zoop.boing.bad. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1 cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS boing.bad. NS boing.bad.
NS zoop.boing.bad.
NS ptang.zoop.boing.bad.
NS icky.ptang.zoop.boing.bad.
NS icky.icky.ptang.zoop.boing.bad.
A icky.icky.icky.ptang.zoop.boing.bad. A icky.icky.icky.ptang.zoop.boing.bad.
A ns3.bad.
AAAA ns3.bad.
NS name.bad.
NS name.bad.
A a.bit.longer.ns.name.bad.
AAAA a.bit.longer.ns.name.bad.
__EOF __EOF
echo "A icky.icky.icky.ptang.zoop.boing.bad." | diff ans3/query.log - > /dev/null || ret=1
echo "A icky.icky.icky.ptang.zoop.boing.bad." | diff ans4/query.log - > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@ -102,14 +156,30 @@ n=`expr $n + 1`
echo_i "query for .slow is properly minimized when qname-minimization is on ($n)" echo_i "query for .slow is properly minimized when qname-minimization is on ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.4 flush $RNDCCMD 10.53.0.6 flush
$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.slow. @10.53.0.4 > dig.out.test$n $DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.slow. @10.53.0.6 > dig.out.test$n
sleep 5
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "icky.icky.icky.ptang.zoop.boing.slow. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1 cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS boing.slow. NS boing.slow.
NS zoop.boing.slow. NS zoop.boing.slow.
A ns3.slow.
AAAA ns3.slow.
NS name.slow.
NS name.slow.
NS ns.name.slow.
NS ns.name.slow.
NS longer.ns.name.slow.
NS longer.ns.name.slow.
A a.bit.longer.ns.name.slow.
AAAA a.bit.longer.ns.name.slow.
__EOF
cat << __EOF | diff ans3/query.log - > /dev/null || ret=1
NS ptang.zoop.boing.slow. NS ptang.zoop.boing.slow.
NS icky.ptang.zoop.boing.slow. NS icky.ptang.zoop.boing.slow.
__EOF
cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.icky.ptang.zoop.boing.slow. NS icky.icky.ptang.zoop.boing.slow.
A icky.icky.icky.ptang.zoop.boing.slow. A icky.icky.icky.ptang.zoop.boing.slow.
__EOF __EOF
@ -117,12 +187,13 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
n=`expr $n + 1` n=`expr $n + 1`
echo_i "query for .ip6.arpa succeds and skips on boundaries when qname-minimization is on ($n)" echo_i "query for .ip6.arpa succeds and skips on proper boundaries when qname-minimization is on ($n)"
ret=0 ret=0
$CLEANQL $CLEANQL
$RNDCCMD 10.53.0.4 flush $RNDCCMD 10.53.0.6 flush
$DIG $DIGOPTS -x 2001:4f8::1 @10.53.0.4 > dig.out.test$n $DIG $DIGOPTS -x 2001:4f8::1 @10.53.0.6 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa. 1 IN PTR nee.com." dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1 cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS 1.0.0.2.ip6.arpa. NS 1.0.0.2.ip6.arpa.
NS 8.f.4.0.1.0.0.2.ip6.arpa. NS 8.f.4.0.1.0.0.2.ip6.arpa.
@ -134,5 +205,57 @@ __EOF
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "query for multiple label name skips after 3rd no-delegation response ($n)"
ret=0
$CLEANQL
$RNDCCMD 10.53.0.6 flush
$DIG $DIGOPTS many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.good. @10.53.0.6 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.good. 1 IN A 192.0.2.2" dig.out.test$n > /dev/null || ret=1
# We skipped after third no-delegation.
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS z.good.
NS y.z.good.
NS x.y.z.good.
A many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.good.
__EOF
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "query for multiple label name skips after 7th label ($n)"
ret=0
$CLEANQL
$RNDCCMD 10.53.0.6 flush
$DIG $DIGOPTS more.icky.icky.icky.ptang.zoop.boing.good. @10.53.0.6 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "more.icky.icky.icky.ptang.zoop.boing.good. 1 IN A 192.0.2.2" dig.out.test$n > /dev/null || ret=1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS boing.good.
NS zoop.boing.good.
A ns3.good.
AAAA ns3.good.
NS name.good.
NS name.good.
NS ns.name.good.
NS ns.name.good.
NS longer.ns.name.good.
NS longer.ns.name.good.
A a.bit.longer.ns.name.good.
AAAA a.bit.longer.ns.name.good.
__EOF
cat << __EOF | diff ans3/query.log - > /dev/null || ret=1
NS ptang.zoop.boing.good.
NS icky.ptang.zoop.boing.good.
__EOF
# There's no NS icky.icky.ptang.zoop.boing.good. query - we skipped it.
cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.icky.ptang.zoop.boing.good.
A more.icky.icky.icky.ptang.zoop.boing.good.
__EOF
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status" echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1 [ $status -eq 0 ] || exit 1

View File

@ -4029,6 +4029,14 @@ fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
nameservers = &rdataset; nameservers = &rdataset;
options |= DNS_FETCHOPT_UNSHARED; options |= DNS_FETCHOPT_UNSHARED;
} }
if (adb->view->qminimization) {
options |= DNS_FETCHOPT_QMINIMIZE;
options |= DNS_FETCHOPT_QMIN_SKIP_ON_IP6A;
if (adb->view->qmin_strict) {
options |= DNS_FETCHOPT_QMIN_STRICT;
}
}
fetch = new_adbfetch(adb); fetch = new_adbfetch(adb);
if (fetch == NULL) { if (fetch == NULL) {

View File

@ -141,6 +141,10 @@ typedef enum {
#define DNS_RESOLVER_CHECKNAMES 0x01 #define DNS_RESOLVER_CHECKNAMES 0x01
#define DNS_RESOLVER_CHECKNAMESFAIL 0x02 #define DNS_RESOLVER_CHECKNAMESFAIL 0x02
#define DNS_QMIN_MAXLABELS 7
#define DNS_QMIN_MAX_NO_DELEGATION 3
#define DNS_MAX_LABELS 127
isc_result_t isc_result_t
dns_resolver_create(dns_view_t *view, dns_resolver_create(dns_view_t *view,
isc_taskmgr_t *taskmgr, isc_taskmgr_t *taskmgr,

View File

@ -265,6 +265,7 @@ struct fetchctx {
unsigned int dbucketnum; unsigned int dbucketnum;
char * info; char * info;
isc_mem_t * mctx; isc_mem_t * mctx;
isc_stdtime_t now;
/*% Locked by appropriate bucket lock. */ /*% Locked by appropriate bucket lock. */
fetchstate state; fetchstate state;
@ -689,7 +690,7 @@ typedef struct respctx {
isc_boolean_t ns_in_answer; /* NS may be in the answer section */ isc_boolean_t ns_in_answer; /* NS may be in the answer section */
isc_boolean_t negative; /* is this a negative response? */ isc_boolean_t negative; /* is this a negative response? */
isc_stdtime_t now; /* time info */ isc_stdtime_t now; /* time info */
isc_time_t tnow; isc_time_t tnow;
isc_time_t *finish; isc_time_t *finish;
@ -2542,8 +2543,8 @@ resquery_send(resquery_t *query) {
fctx->timeout = ISC_FALSE; fctx->timeout = ISC_FALSE;
/* /*
* Use EDNS0, unless the caller doesn't want it, or we know that * Use EDNS0, unless the caller doesn't want it, or we know that the
* the remote server doesn't like it. * remote server doesn't like it.
*/ */
if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
@ -4437,7 +4438,7 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client,
return (ISC_R_NOMEMORY); return (ISC_R_NOMEMORY);
} }
event->result = DNS_R_SERVFAIL; event->result = DNS_R_SERVFAIL;
event->qtype = fctx->type; event->qtype = fctx->fulltype;
event->db = NULL; event->db = NULL;
event->node = NULL; event->node = NULL;
event->rdataset = rdataset; event->rdataset = rdataset;
@ -4559,6 +4560,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
fctx->minimized = isc_boolean_false; fctx->minimized = isc_boolean_false;
fctx->ip6arpaskip = isc_boolean_false; fctx->ip6arpaskip = isc_boolean_false;
fctx->qmin_labels = 1; fctx->qmin_labels = 1;
isc_stdtime_get(&fctx->now);
ISC_LIST_INIT(fctx->queries); ISC_LIST_INIT(fctx->queries);
ISC_LIST_INIT(fctx->finds); ISC_LIST_INIT(fctx->finds);
ISC_LIST_INIT(fctx->altfinds); ISC_LIST_INIT(fctx->altfinds);
@ -7423,7 +7425,6 @@ rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent,
TIME_NOW(&rctx->tnow); TIME_NOW(&rctx->tnow);
rctx->finish = &rctx->tnow; rctx->finish = &rctx->tnow;
isc_stdtime_get(&rctx->now); isc_stdtime_get(&rctx->now);
} }
/* /*
@ -8497,7 +8498,20 @@ rctx_answer_none(respctx_t *rctx) {
} else { } else {
log_formerr(fctx, "invalid response"); log_formerr(fctx, "invalid response");
} }
/*
* If we're minimizing in relaxed mode, retry with full name,
* just to be safe. The error will be logged.
*/
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, "XXX %d %d", fctx->minimized, fctx->options & DNS_FETCHOPT_QMIN_STRICT);
if (fctx->minimized &&
!(fctx->options & DNS_FETCHOPT_QMIN_STRICT)) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
"disabling qname minimization for '%s'"
" due to formerr", fctx->info);
fctx->qmin_labels = DNS_MAX_LABELS+1;
return rctx_answer_minimized(rctx);
}
return (DNS_R_FORMERR); return (DNS_R_FORMERR);
} }
@ -8523,12 +8537,17 @@ rctx_answer_none(respctx_t *rctx) {
* If we're doing qname minimization this is an empty non-terminal, add * If we're doing qname minimization this is an empty non-terminal, add
* the next label to query and restart it. * the next label to query and restart it.
*/ */
if (fctx->minimized && if (fctx->minimized && fctx->rmessage->rcode == dns_rcode_noerror) {
(fctx->rmessage->rcode == dns_rcode_noerror || return rctx_answer_minimized(rctx);
!(fctx->options & DNS_FETCHOPT_QMIN_STRICT))) { }
/*
* Workaround for broken servers in relaxed mode - if we hit an
* NXDOMAIN we go straight to the full query.
*/
if (fctx->minimized && !(fctx->options & DNS_FETCHOPT_QMIN_STRICT)) {
fctx->qmin_labels = DNS_MAX_LABELS+1;
return rctx_answer_minimized(rctx); return rctx_answer_minimized(rctx);
} }
/* /*
* Since we're not doing a referral, we don't want to cache any * Since we're not doing a referral, we don't want to cache any
* NS RRs we may have found. * NS RRs we may have found.
@ -9079,7 +9098,7 @@ rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
} }
result = dns_view_findzonecut(fctx->res->view, result = dns_view_findzonecut(fctx->res->view,
name, fname, name, fname,
rctx->now, findoptions, fctx->now, findoptions,
ISC_TRUE, ISC_TRUE, ISC_TRUE, ISC_TRUE,
&fctx->nameservers, &fctx->nameservers,
NULL); NULL);
@ -10283,6 +10302,10 @@ fctx_minimize_qname(fetchctx_t *fctx) {
} else if (dlabels + fctx->qmin_labels > 19) { } else if (dlabels + fctx->qmin_labels > 19) {
fctx->qmin_labels = 35 - dlabels; fctx->qmin_labels = 35 - dlabels;
} }
} else if (dlabels + fctx->qmin_labels > DNS_QMIN_MAXLABELS) {
fctx->qmin_labels = DNS_MAX_LABELS + 1;
} else if (fctx->qmin_labels > DNS_QMIN_MAX_NO_DELEGATION) {
fctx->qmin_labels = DNS_MAX_LABELS + 1;
} }
if (dlabels + fctx->qmin_labels < nlabels) { if (dlabels + fctx->qmin_labels < nlabels) {
/* /*

View File

@ -130,6 +130,7 @@ static cfg_type_t cfg_type_optional_uint32;
static cfg_type_t cfg_type_options; static cfg_type_t cfg_type_options;
static cfg_type_t cfg_type_portiplist; static cfg_type_t cfg_type_portiplist;
static cfg_type_t cfg_type_printtime; static cfg_type_t cfg_type_printtime;
static cfg_type_t cfg_type_qminmethod;
static cfg_type_t cfg_type_querysource4; static cfg_type_t cfg_type_querysource4;
static cfg_type_t cfg_type_querysource6; static cfg_type_t cfg_type_querysource6;
static cfg_type_t cfg_type_querysource; static cfg_type_t cfg_type_querysource;
@ -1937,8 +1938,7 @@ view_clauses[] = {
{ "preferred-glue", &cfg_type_astring, 0 }, { "preferred-glue", &cfg_type_astring, 0 },
{ "prefetch", &cfg_type_prefetch, 0 }, { "prefetch", &cfg_type_prefetch, 0 },
{ "provide-ixfr", &cfg_type_boolean, 0 }, { "provide-ixfr", &cfg_type_boolean, 0 },
{ "qname-minimization", &cfg_type_boolean, 0 }, { "qname-minimization", &cfg_type_qminmethod, 0 },
{ "qname-minimization-strict", &cfg_type_boolean, 0 },
/* /*
* Note that the query-source option syntax is different * Note that the query-source option syntax is different
* from the other -source options. * from the other -source options.
@ -2951,6 +2951,15 @@ static cfg_type_t cfg_type_optional_keyref = {
doc_optional_keyvalue, &cfg_rep_string, &key_kw doc_optional_keyvalue, &cfg_rep_string, &key_kw
}; };
static const char *qminmethod_enums[] = {
"strict", "relaxed", "disabled", NULL
};
static cfg_type_t cfg_type_qminmethod = {
"qminmethod", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
&cfg_rep_string, qminmethod_enums
};
#ifdef HAVE_GEOIP #ifdef HAVE_GEOIP
/* /*
* "geoip" ACL element: * "geoip" ACL element:

View File

@ -1730,12 +1730,14 @@
./bin/tests/system/pkcs11ssl/tests.sh SH 2014,2016,2018 ./bin/tests/system/pkcs11ssl/tests.sh SH 2014,2016,2018
./bin/tests/system/pkcs11ssl/usepkcs11 X 2014,2018 ./bin/tests/system/pkcs11ssl/usepkcs11 X 2014,2018
./bin/tests/system/qname-minimization/ans2/ans.py PYTHON 2018 ./bin/tests/system/qname-minimization/ans2/ans.py PYTHON 2018
./bin/tests/system/qname-minimization/ans3/ans.py PYTHON 2018
./bin/tests/system/qname-minimization/ans4/ans.py PYTHON 2018
./bin/tests/system/qname-minimization/clean.sh SH 2018 ./bin/tests/system/qname-minimization/clean.sh SH 2018
./bin/tests/system/qname-minimization/ns1/named.conf.in CONF-C 2018 ./bin/tests/system/qname-minimization/ns1/named.conf.in CONF-C 2018
./bin/tests/system/qname-minimization/ns1/root.db ZONE 2018 ./bin/tests/system/qname-minimization/ns1/root.db ZONE 2018
./bin/tests/system/qname-minimization/ns3/named.conf.in CONF-C 2018
./bin/tests/system/qname-minimization/ns4/named.conf.in CONF-C 2018
./bin/tests/system/qname-minimization/ns5/named.conf.in CONF-C 2018 ./bin/tests/system/qname-minimization/ns5/named.conf.in CONF-C 2018
./bin/tests/system/qname-minimization/ns6/named.conf.in CONF-C 2018
./bin/tests/system/qname-minimization/ns7/named.conf.in CONF-C 2018
./bin/tests/system/qname-minimization/setup.sh SH 2018 ./bin/tests/system/qname-minimization/setup.sh SH 2018
./bin/tests/system/qname-minimization/tests.sh SH 2018 ./bin/tests/system/qname-minimization/tests.sh SH 2018
./bin/tests/system/reclimit/README TXT.BRIEF 2014,2016,2017,2018 ./bin/tests/system/reclimit/README TXT.BRIEF 2014,2016,2017,2018