provide-ixfr true;\n\
query-source address *;\n\
query-source-v6 address *;\n\
+ qname-minimization no;\n\
+ qname-minimization-strict no;\n\
recursion true;\n\
request-expire true;\n\
request-ixfr true;\n\
INSIST(result == ISC_R_SUCCESS);
view->recursion = cfg_obj_asboolean(obj);
+ 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);
+
obj = NULL;
result = named_config_get(maps, "auth-nxdomain", &obj);
INSIST(result == ISC_R_SUCCESS);
--- /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:
+# ns2.good. IN A 10.53.0.2
+# icky.icky.icky.ptang.zoop.boing.good. A 192.0.2.1
+# 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
+#
+# For 1.0.0.2.ip6.arpa it serves
+# 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. IN PTR nee.com.
+# 1.0.0.2.ip6.arpa. IN NS ns2.good
+# ip6.arpa. IN NS ns2.good
+############################################################################
+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("1.0.0.2.ip6.arpa."):
+ # Direct query - give direct answer
+ if lqname == "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." and rrtype == PTR:
+ # Direct query - give direct answer
+ r.answer.append(dns.rrset.from_text("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."))
+ elif lqname == "1.0.0.2.ip6.arpa." and rrtype == NS:
+ # NS query at the apex
+ r.answer.append(dns.rrset.from_text("1.0.0.2.ip6.arpa.", 1, IN, NS, "ns2.good."))
+ elif "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.".endswith(lqname):
+ # NODATA answer
+ r.authority.append(dns.rrset.from_text("1.0.0.2.ip6.arpa.", 1, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
+ else:
+ # NXDOMAIN
+ r.authority.append(dns.rrset.from_text("1.0.0.2.ip6.arpa.", 1, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
+ r.set_rcode(NXDOMAIN)
+ return r
+ elif lqname.endswith("ip6.arpa."):
+ if lqname == "ip6.arpa." and rrtype == NS:
+ # NS query at the apex
+ r.answer.append(dns.rrset.from_text("ip6.arpa.", 1, IN, NS, "ns2.good."))
+ elif "1.0.0.2.ip6.arpa.".endswith(lqname):
+ # NODATA answer
+ r.authority.append(dns.rrset.from_text("ip6.arpa.", 1, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
+ else:
+ # NXDOMAIN
+ r.authority.append(dns.rrset.from_text("ip6.arpa.", 1, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
+ r.set_rcode(NXDOMAIN)
+ return r
+ elif 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 == "" 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"))
+ 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):
+ r.set_rcode(NXDOMAIN)
+ 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.2"
+ip6 = "fd92:7065:b8e:ffff::2"
+
+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
+#!/bin/sh
+#
+# 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.
+
+rm -f ns*/named.conf
+rm -f */named.memstats
+rm -f */named.run
+rm -f dig.out.*
+rm -f ns*/named.lock
+rm -f ans2/query.log
--- /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.
+ */
+
+// NS1
+
+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 { none; };
+ recursion no;
+ notify yes;
+};
+
+zone "." {
+ type master;
+ file "root.db";
+};
--- /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.
+
+$TTL 20
+. IN SOA wpk.isc.org. a.root.servers.nil. (
+ 2000042100 ; serial
+ 600 ; refresh
+ 600 ; retry
+ 1200 ; expire
+ 2 ; minimum
+ )
+. NS a.root-servers.nil.
+a.root-servers.nil. A 10.53.0.1
+ip6.arpa. NS ns2.good.
+
+good. NS ns2.good.
+ns2.good. A 10.53.0.2
+
+bad. NS ns2.bad.
+ns2.bad. A 10.53.0.2
+
+slow NS ns2.slow.
+ns2.slow. A 10.53.0.2
+
+horrible. NS ns2.horrible.
+ns2.horrible. A 10.53.0.2
--- /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.
+ */
+
+// NS3
+
+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 { none; };
+ recursion yes;
+ qname-minimization no;
+ qname-minimization-strict no;
+ querylog yes;
+ resolver-query-timeout 30;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
+
+controls {
+ inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
--- /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.
+ */
+
+// NS4
+
+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 { none; };
+ recursion yes;
+ qname-minimization yes;
+ qname-minimization-strict yes;
+ querylog yes;
+ resolver-query-timeout 30;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
--- /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.
+ */
+
+// NS5
+
+options {
+ query-source address 10.53.0.5;
+ notify-source 10.53.0.5;
+ transfer-source 10.53.0.5;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.5; };
+ listen-on-v6 { none; };
+ recursion yes;
+ qname-minimization yes;
+ qname-minimization-strict no;
+ querylog yes;
+ resolver-query-timeout 30;
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
+
+controls {
+ inet 10.53.0.5 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
--- /dev/null
+#!/bin/sh -e
+#
+# 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.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+$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
--- /dev/null
+#!/bin/sh
+#
+# 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.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+DIGOPTS="-p ${PORT}"
+RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
+CLEANQL="rm -f ans2/query.log"
+status=0
+n=0
+
+n=`expr $n + 1`
+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
+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
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+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
+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
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+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
+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
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+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
+grep "status: NOERROR" 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.
+NS ptang.zoop.boing.good.
+NS icky.ptang.zoop.boing.good.
+NS icky.icky.ptang.zoop.boing.good.
+A icky.icky.icky.ptang.zoop.boing.good.
+__EOF
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "query for .bad fails when qname-minimization is on and 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
+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)"
+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
+grep "status: NOERROR" 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.
+__EOF
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+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
+grep "status: NOERROR" 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.
+NS ptang.zoop.boing.slow.
+NS icky.ptang.zoop.boing.slow.
+NS icky.icky.ptang.zoop.boing.slow.
+A icky.icky.icky.ptang.zoop.boing.slow.
+__EOF
+if [ $ret != 0 ]; then echo_i "failed"; fi
+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)"
+ret=0
+$CLEANQL
+$RNDCCMD 10.53.0.4 flush
+$DIG $DIGOPTS -x 2001:4f8::1 @10.53.0.4 > dig.out.test$n
+grep "status: NOERROR" 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.
+NS 0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
+NS 0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
+NS 0.0.0.0.0.0.0.0.8.f.4.0.1.0.0.2.ip6.arpa.
+PTR 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.
+__EOF
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+echo_i "exit status: $status"
+[ $status -eq 0 ] || exit 1
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
+ qname-minimization <boolean>;
+ qname-minimization-strict <boolean>;
query-source ( ( [ address ] ( <ipv4_address> | * ) [ port (
<integer> | * ) ] ) | ( [ [ address ] ( <ipv4_address> | * ) ]
port ( <integer> | * ) ) ) [ dscp <integer> ];
/* RESERVED ECS 0x2000 */
/* RESERVED TCPCLIENT 0x4000 */
#define DNS_FETCHOPT_NOCACHED 0x8000 /*%< Force cache update. */
+#define DNS_FETCHOPT_QMINIMIZE 0x00010000 /*%< Use qname minimization. */
+#define DNS_FETCHOPT_QMIN_STRICT 0x00020000 /*%< Do not work around servers that
+ return errors on non-empty
+ terminals. */
+#define DNS_FETCHOPT_QMIN_SKIP_ON_IP6A 0x00040000 /*%< Skip some labels when
+ doing qname minimization on
+ ip6.arpa. */
/* Reserved in use by adb.c 0x00400000 */
#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000
dns_rdatatype_t type,
const dns_name_t *domain, dns_rdataset_t *nameservers,
dns_forwarders_t *forwarders,
- const isc_sockaddr_t *client, isc_uint16_t id,
+ const isc_sockaddr_t *client, dns_messageid_t id,
unsigned int options, unsigned int depth,
isc_counter_t *qc, isc_task_t *task,
isc_taskaction_t action, void *arg,
dns_order_t * order;
dns_fwdtable_t * fwdtable;
isc_boolean_t recursion;
+ isc_boolean_t qminimization;
+ isc_boolean_t qmin_strict;
isc_boolean_t auth_nxdomain;
isc_boolean_t use_glue_cache;
isc_boolean_t minimal_any;
/*% Not locked. */
unsigned int magic;
dns_resolver_t * res;
- dns_name_t name;
- dns_rdatatype_t type;
+ dns_name_t fullname;
+ dns_rdatatype_t fulltype;
unsigned int options;
unsigned int bucketnum;
unsigned int dbucketnum;
isc_event_t control_event;
ISC_LINK(struct fetchctx) link;
ISC_LIST(dns_fetchevent_t) events;
+
/*% Locked by task event serialization. */
dns_name_t domain;
dns_rdataset_t nameservers;
isc_boolean_t ns_ttl_ok;
isc_uint32_t ns_ttl;
isc_counter_t * qc;
+ isc_boolean_t minimized;
+ unsigned int qmin_labels;
+ isc_boolean_t ip6arpaskip;
+ dns_name_t name;
+ dns_rdatatype_t type;
/*%
* The number of events we're waiting for.
}
#endif
+static unsigned char ip6_arpa_data[] = "\003IP6\004ARPA";
+static unsigned char ip6_arpa_offsets[] = { 0, 4, 9 };
+static const dns_name_t ip6_arpa =
+ DNS_NAME_INITABSOLUTE(ip6_arpa_data, ip6_arpa_offsets);
+
static void destroy(dns_resolver_t *res);
static void empty_bucket(dns_resolver_t *res);
static isc_result_t resquery_send(resquery_t *query);
static void resquery_connected(isc_task_t *task, isc_event_t *event);
static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying,
isc_boolean_t badcache);
+void fctx_minimize_qname(fetchctx_t *fctx);
static void fctx_destroy(fetchctx_t *fctx);
static isc_boolean_t fctx_unlink(fetchctx_t *fctx);
static isc_result_t ncache_adderesult(dns_message_t *message,
static isc_result_t
rctx_answer_none(respctx_t *rctx);
+static void
+rctx_follow_referral(respctx_t *rctx);
+
+static isc_result_t
+rctx_answer_minimized(respctx_t *rctx);
+
static void
rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
isc_result_t result);
dns_name_free(&fctx->domain, fctx->mctx);
if (dns_rdataset_isassociated(&fctx->nameservers))
dns_rdataset_disassociate(&fctx->nameservers);
+ dns_name_free(&fctx->fullname, fctx->mctx);
dns_name_free(&fctx->name, fctx->mctx);
dns_db_detach(&fctx->cache);
dns_adb_detach(&fctx->adb);
result = dns_name_dup(name, mctx, &fctx->name);
if (result != ISC_R_SUCCESS)
goto cleanup_info;
+ dns_name_init(&fctx->fullname, NULL);
+ result = dns_name_dup(name, mctx, &fctx->fullname);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_name;
dns_name_init(&fctx->domain, NULL);
dns_rdataset_init(&fctx->nameservers);
+ fctx->fulltype = type;
fctx->type = type;
fctx->options = options;
/*
fctx->want_shutdown = ISC_FALSE;
fctx->cloned = ISC_FALSE;
fctx->depth = depth;
+ fctx->minimized = isc_boolean_false;
+ fctx->ip6arpaskip = isc_boolean_false;
+ fctx->qmin_labels = 1;
ISC_LIST_INIT(fctx->queries);
ISC_LIST_INIT(fctx->finds);
ISC_LIST_INIT(fctx->altfinds);
*/
result = dns_name_dup(fname, mctx, &fctx->domain);
if (result != ISC_R_SUCCESS)
- goto cleanup_name;
+ goto cleanup_fullname;
}
} else {
result = dns_name_dup(domain, mctx, &fctx->domain);
if (result != ISC_R_SUCCESS)
- goto cleanup_name;
+ goto cleanup_fullname;
dns_rdataset_clone(nameservers, &fctx->nameservers);
fctx->ns_ttl = fctx->nameservers.ttl;
fctx->ns_ttl_ok = ISC_TRUE;
ISC_LINK_INIT(fctx, link);
fctx->magic = FCTX_MAGIC;
+ /*
+ * If qname minimization is enabled we need to trim
+ * the name in fctx to proper length.
+ */
+ if (options & DNS_FETCHOPT_QMINIMIZE) {
+ fctx->ip6arpaskip = (options & DNS_FETCHOPT_QMIN_SKIP_ON_IP6A) && dns_name_issubdomain(&fctx->name, &ip6_arpa);
+ fctx_minimize_qname(fctx);
+ }
+
ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
LOCK(&res->nlock);
if (dns_rdataset_isassociated(&fctx->nameservers))
dns_rdataset_disassociate(&fctx->nameservers);
+ cleanup_fullname:
+ dns_name_free(&fctx->fullname, mctx);
+
cleanup_name:
dns_name_free(&fctx->name, mctx);
unsigned int valoptions = 0;
isc_boolean_t checknta = ISC_TRUE;
+ FCTXTRACE("cache_name");
+
/*
* The appropriate bucket lock must be held.
*/
#ifndef CHECK_FOR_GLUE_IN_ANSWER
#define CHECK_FOR_GLUE_IN_ANSWER 0
#endif
-#if CHECK_FOR_GLUE_IN_ANSWER
static isc_result_t
check_answer(void *arg, const dns_name_t *addname, dns_rdatatype_t type) {
return (check_section(arg, addname, type, DNS_SECTION_ANSWER));
}
-#endif
static isc_boolean_t
is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
- if ((fctx->rmessage->flags & DNS_MESSAGEFLAG_AA) != 0 ||
+ if (fctx->minimized) {
+ result = rctx_answer_minimized(rctx);
+ if (result != ISC_R_SUCCESS) {
+ FCTXTRACE3("rctx_answer_minimized", result);
+ }
+ } else if ((fctx->rmessage->flags & DNS_MESSAGEFLAG_AA) != 0 ||
ISFORWARDER(query->addrinfo))
{
result = rctx_answer_positive(rctx);
return (rctx->result);
}
+ /*
+ * 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))) {
+ 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.
check_answer, fctx);
}
#endif
+ if (fctx->minimized) {
+ (void)dns_rdataset_additionaldata(rctx->ns_rdataset,
+ check_answer, fctx);
+ }
fctx->attributes &= ~FCTX_ATTR_GLUING;
/*
log_ns_ttl(fctx, "DELEGATION");
rctx->result = DNS_R_DELEGATION;
+ rctx_follow_referral(rctx);
+ if (rctx->fctx->minimized) {
+ /*
+ * Reset the value
+ */
+ fctx->qmin_labels = 1;
+ fctx_minimize_qname(rctx->fctx);
+ }
+ return (ISC_R_COMPLETE);
+}
+
+/*
+ * rctx_answer_minimized():
+ * Handles a positive response to a qname-minimized query.
+ */
+static isc_result_t
+rctx_answer_minimized(respctx_t *rctx) {
+ fetchctx_t *fctx = rctx->fctx;
+
+ FCTXTRACE("rctx_answer_minimized");
+ if (dns_rdataset_isassociated(&fctx->nameservers)) {
+ dns_rdataset_disassociate(&fctx->nameservers);
+ }
+ rctx->result = DNS_R_DELEGATION;
+ rctx_follow_referral(rctx);
+ fctx->qmin_labels++;
+ fctx_minimize_qname(rctx->fctx);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+rctx_follow_referral(respctx_t *rctx) {
/*
* Reinitialize 'rctx' to prepare for following the delegation:
* set the get_nameservers and next_server flags appropriately and
rctx->fctx->neterr = 0;
rctx->fctx->badresp = 0;
rctx->fctx->adberr = 0;
-
- return (ISC_R_COMPLETE);
}
/*
ISC_LIST_EMPTY(fctx->events))
return (ISC_FALSE);
- if (fctx->type != type || fctx->options != options)
+ if (fctx->fulltype != type || fctx->options != options)
return (ISC_FALSE);
- return (dns_name_equal(&fctx->name, name));
+ return (dns_name_equal(&fctx->fullname, name));
}
static inline void
"fetch: %s/%s", namebuf, typebuf);
}
+void
+fctx_minimize_qname(fetchctx_t *fctx) {
+ /* XXXWPK TODO we should update info to show that this query is minimized */
+ unsigned int dlabels, nlabels;
+
+ dlabels = dns_name_countlabels(&fctx->domain);
+ nlabels = dns_name_countlabels(&fctx->fullname);
+ dns_name_free(&fctx->name, fctx->mctx);
+ dns_name_init(&fctx->name, NULL);
+ if (fctx->ip6arpaskip) {
+ /*
+ * For ip6.arpa we want to skip some of the labels, with boundaries
+ * at /16, /32, /48, /56, /64 and /128
+ * in 'label count' terms that's equal to
+ * 7 11 15 17 19 35
+ * We fix fctx->qmin_labels to point to the nearest boundary
+ */
+ if (dlabels + fctx->qmin_labels < 7) {
+ fctx->qmin_labels = 7 - dlabels;
+ } else if (dlabels + fctx->qmin_labels < 11) {
+ fctx->qmin_labels = 11 - dlabels;
+ } else if (dlabels + fctx->qmin_labels < 15) {
+ fctx->qmin_labels = 15 - dlabels;
+ } else if (dlabels + fctx->qmin_labels < 17) {
+ fctx->qmin_labels = 17 - dlabels;
+ } else if (dlabels + fctx->qmin_labels < 19) {
+ fctx->qmin_labels = 19 - dlabels;
+ } else if (dlabels + fctx->qmin_labels > 19) {
+ fctx->qmin_labels = 35 - dlabels;
+ }
+ }
+ if (dlabels + fctx->qmin_labels < nlabels) {
+ /*
+ * We want to query for [qmin_labels from fctx->fullname] + fctx->domain
+ */
+ dns_fixedname_t fname;
+ dns_fixedname_init(&fname);
+ dns_name_split(&fctx->fullname,
+ dlabels + fctx->qmin_labels,
+ NULL, dns_fixedname_name(&fname));
+ dns_name_dup(dns_fixedname_name(&fname), fctx->mctx, &fctx->name);
+ fctx->type = dns_rdatatype_ns;
+ fctx->minimized = isc_boolean_true;
+ } else {
+ /* Minimization is done, we'll ask for whole qname */
+ fctx->type = fctx->fulltype;
+ dns_name_dup(&fctx->fullname, fctx->mctx, &fctx->name);
+ fctx->minimized = isc_boolean_false;
+ }
+}
+
isc_result_t
dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
dns_rdatatype_t type,
* Initialize configuration data with default values.
*/
view->recursion = ISC_TRUE;
+ view->qminimization = ISC_FALSE;
+ view->qmin_strict = ISC_FALSE;
view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
view->enablednssec = ISC_TRUE;
view->enablevalidation = ISC_TRUE;
{ "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 },
/*
* Note that the query-source option syntax is different
* from the other -source options.
} else if (!client->view->enablevalidation)
client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
+ if (client->view->qminimization) {
+ client->query.fetchoptions |= DNS_FETCHOPT_QMINIMIZE |
+ DNS_FETCHOPT_QMIN_SKIP_ON_IP6A;
+ if (client->view->qmin_strict) {
+ client->query.fetchoptions |=
+ DNS_FETCHOPT_QMIN_STRICT;
+ }
+ }
+
/*
* Allow glue NS records to be added to the authority section
* if the answer is secure.
./bin/tests/system/pkcs11ssl/setup.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/qname-minimization/ans2/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/setup.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/ans2/ans.pl PERL 2014,2015,2016,2017,2018
./bin/tests/system/reclimit/ans7/ans.pl PERL 2014,2016,2018