provide-ixfr true;\n\
query-source address *;\n\
query-source-v6 address *;\n\
- qname-minimization no;\n\
- qname-minimization-strict no;\n\
+ qname-minimization relaxed;\n\
recursion true;\n\
request-expire true;\n\
request-ixfr true;\n\
obj = NULL;
result = named_config_get(maps, "qname-minimization", &obj);
INSIST(result == ISC_R_SUCCESS);
- view->qminimization = cfg_obj_asboolean(obj);
-
- obj = NULL;
- result = named_config_get(maps, "qname-minimization-strict", &obj);
- INSIST(result == ISC_R_SUCCESS);
- view->qmin_strict = cfg_obj_asboolean(obj);
+ const char * qminmode = cfg_obj_asstring(obj);
+ INSIST(qminmode != NULL);
+ if (!strcmp(qminmode, "strict")) {
+ view->qminimization = ISC_TRUE;
+ view->qmin_strict = ISC_TRUE;
+ } 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;
result = named_config_get(maps, "auth-nxdomain", &obj);
# Respond to a DNS query.
# For good. it serves:
# 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
#
# For slow. it works the same as for good., but each response is delayed by 400 miliseconds
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"))
+ if lqname.endswith("zoop.boing."):
+ 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:
r.answer.append(dns.rrset.from_text(suffix, 1, IN, NS, "ns2." + suffix))
elif lqname == "ns2." and rrtype == A:
r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, A, "10.53.0.2"))
elif lqname == "ns2." and rrtype == AAAA:
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:
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)
if slow:
- time.sleep(0.4)
+ time.sleep(0.2)
return r
--- /dev/null
+############################################################################
+# 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
--- /dev/null
+############################################################################
+# 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
rm -f */named.run
rm -f dig.out.*
rm -f ns*/named.lock
-rm -f ans2/query.log
+rm -f ans*/query.log
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion yes;
- qname-minimization yes;
- qname-minimization-strict no;
+ qname-minimization disabled;
querylog yes;
resolver-query-timeout 30;
};
* information regarding copyright ownership.
*/
-// NS3
+// NS6
options {
- query-source address 10.53.0.3;
- notify-source 10.53.0.3;
- transfer-source 10.53.0.3;
+ query-source address 10.53.0.6;
+ notify-source 10.53.0.6;
+ transfer-source 10.53.0.6;
port @PORT@;
pid-file "named.pid";
- listen-on { 10.53.0.3; };
+ listen-on { 10.53.0.6; };
listen-on-v6 { none; };
recursion yes;
- qname-minimization no;
- qname-minimization-strict no;
+ qname-minimization strict;
querylog yes;
resolver-query-timeout 30;
};
};
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 "." {
* information regarding copyright ownership.
*/
-// NS4
+// NS7
options {
- query-source address 10.53.0.4;
- notify-source 10.53.0.4;
- transfer-source 10.53.0.4;
+ query-source address 10.53.0.7;
+ notify-source 10.53.0.7;
+ transfer-source 10.53.0.7;
port @PORT@;
pid-file "named.pid";
- listen-on { 10.53.0.4; };
+ listen-on { 10.53.0.7; };
listen-on-v6 { none; };
recursion yes;
- qname-minimization yes;
- qname-minimization-strict yes;
+ qname-minimization relaxed;
querylog yes;
resolver-query-timeout 30;
};
};
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 "." {
$SHELL clean.sh
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 ns6/named.conf.in ns6/named.conf
+copy_setports ns7/named.conf.in ns7/named.conf
DIGOPTS="-p ${PORT}"
RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
-CLEANQL="rm -f ans2/query.log"
+CLEANQL="rm -f ans*/query.log"
status=0
n=0
echo_i "query for .good is not minimized when qname-minimization is off ($n)"
ret=0
$CLEANQL
-$RNDCCMD 10.53.0.3 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.good. @10.53.0.3 > dig.out.test$n
+$RNDCCMD 10.53.0.5 flush
+$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
-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
status=`expr $status + $ret`
echo_i "query for .bad is not minimized when qname-minimization is off ($n)"
ret=0
$CLEANQL
-$RNDCCMD 10.53.0.3 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.3 > dig.out.test$n
+$RNDCCMD 10.53.0.5 flush
+$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
-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
status=`expr $status + $ret`
echo_i "query for .slow is not minimized when qname-minimization is off ($n)"
ret=0
$CLEANQL
-$RNDCCMD 10.53.0.3 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.slow. @10.53.0.3 > dig.out.test$n
+$RNDCCMD 10.53.0.5 flush
+$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
-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
status=`expr $status + $ret`
echo_i "query for .good is properly minimized when qname-minimization is on ($n)"
ret=0
$CLEANQL
-$RNDCCMD 10.53.0.4 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.good. @10.53.0.4 > dig.out.test$n
+$RNDCCMD 10.53.0.6 flush
+$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 "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
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
+cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.icky.ptang.zoop.boing.good.
A icky.icky.icky.ptang.zoop.boing.good.
__EOF
status=`expr $status + $ret`
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
$CLEANQL
-$RNDCCMD 10.53.0.4 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.4 > dig.out.test$n
+$RNDCCMD 10.53.0.6 flush
+$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
echo "NS boing.bad." | diff ans2/query.log - > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
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
$CLEANQL
-$RNDCCMD 10.53.0.5 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.bad. @10.53.0.5 > dig.out.test$n
+$RNDCCMD 10.53.0.7 flush
+$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 "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
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 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
+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
status=`expr $status + $ret`
echo_i "query for .slow is properly minimized when qname-minimization is on ($n)"
ret=0
$CLEANQL
-$RNDCCMD 10.53.0.4 flush
-$DIG $DIGOPTS icky.icky.icky.ptang.zoop.boing.slow. @10.53.0.4 > dig.out.test$n
+$RNDCCMD 10.53.0.6 flush
+$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 "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
NS 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 icky.ptang.zoop.boing.slow.
+__EOF
+cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.icky.ptang.zoop.boing.slow.
A icky.icky.icky.ptang.zoop.boing.slow.
__EOF
status=`expr $status + $ret`
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
$CLEANQL
-$RNDCCMD 10.53.0.4 flush
-$DIG $DIGOPTS -x 2001:4f8::1 @10.53.0.4 > dig.out.test$n
+$RNDCCMD 10.53.0.6 flush
+$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 "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
NS 1.0.0.2.ip6.arpa.
NS 8.f.4.0.1.0.0.2.ip6.arpa.
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 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"
[ $status -eq 0 ] || exit 1
nameservers = &rdataset;
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);
if (fetch == NULL) {
#define DNS_RESOLVER_CHECKNAMES 0x01
#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
dns_resolver_create(dns_view_t *view,
isc_taskmgr_t *taskmgr,
unsigned int dbucketnum;
char * info;
isc_mem_t * mctx;
+ isc_stdtime_t now;
/*% Locked by appropriate bucket lock. */
fetchstate state;
isc_boolean_t ns_in_answer; /* NS may be in the answer section */
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 *finish;
fctx->timeout = ISC_FALSE;
/*
- * Use EDNS0, unless the caller doesn't want it, or we know that
- * the remote server doesn't like it.
+ * Use EDNS0, unless the caller doesn't want it, or we know that the
+ * remote server doesn't like it.
*/
if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
return (ISC_R_NOMEMORY);
}
event->result = DNS_R_SERVFAIL;
- event->qtype = fctx->type;
+ event->qtype = fctx->fulltype;
event->db = NULL;
event->node = NULL;
event->rdataset = rdataset;
fctx->minimized = isc_boolean_false;
fctx->ip6arpaskip = isc_boolean_false;
fctx->qmin_labels = 1;
+ isc_stdtime_get(&fctx->now);
ISC_LIST_INIT(fctx->queries);
ISC_LIST_INIT(fctx->finds);
ISC_LIST_INIT(fctx->altfinds);
TIME_NOW(&rctx->tnow);
rctx->finish = &rctx->tnow;
isc_stdtime_get(&rctx->now);
-
}
/*
} else {
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);
}
* If we're doing qname minimization this is an empty non-terminal, add
* the next label to query and restart it.
*/
- if (fctx->minimized &&
- (fctx->rmessage->rcode == dns_rcode_noerror ||
- !(fctx->options & DNS_FETCHOPT_QMIN_STRICT))) {
+ if (fctx->minimized && fctx->rmessage->rcode == dns_rcode_noerror) {
+ return rctx_answer_minimized(rctx);
+ }
+ /*
+ * 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);
}
-
/*
* Since we're not doing a referral, we don't want to cache any
* NS RRs we may have found.
}
result = dns_view_findzonecut(fctx->res->view,
name, fname,
- rctx->now, findoptions,
+ fctx->now, findoptions,
ISC_TRUE, ISC_TRUE,
&fctx->nameservers,
NULL);
} else if (dlabels + fctx->qmin_labels > 19) {
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) {
/*
static cfg_type_t cfg_type_options;
static cfg_type_t cfg_type_portiplist;
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_querysource6;
static cfg_type_t cfg_type_querysource;
{ "preferred-glue", &cfg_type_astring, 0 },
{ "prefetch", &cfg_type_prefetch, 0 },
{ "provide-ixfr", &cfg_type_boolean, 0 },
- { "qname-minimization", &cfg_type_boolean, 0 },
- { "qname-minimization-strict", &cfg_type_boolean, 0 },
+ { "qname-minimization", &cfg_type_qminmethod, 0 },
/*
* Note that the query-source option syntax is different
* from the other -source options.
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
/*
* "geoip" ACL element:
./bin/tests/system/pkcs11ssl/tests.sh SH 2014,2016,2018
./bin/tests/system/pkcs11ssl/usepkcs11 X 2014,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/ns1/named.conf.in CONF-C 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/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/tests.sh SH 2018
./bin/tests/system/reclimit/README TXT.BRIEF 2014,2016,2017,2018