Merge branch '16-qname-minimization' into 'master'

QNAME Minimization

See merge request isc-projects/bind9!253
This commit is contained in:
Witold Krecicki 2018-06-12 07:44:36 -04:00
commit 7dc84eaa8e
51 changed files with 1609 additions and 79 deletions

View file

@ -1,3 +1,5 @@
4970. [func] Add QNAME minimization option to resolver. [GL #16]
4969. [cleanup] Refactor zone logging functions. [GL #269]
4968. [bug] If glue records are signed, attempt to validate them.

View file

@ -183,6 +183,7 @@ options {\n\
notify-source-v6 *;\n\
nsec3-test-zone no;\n\
provide-ixfr true;\n\
qname-minimization relaxed;\n\
query-source address *;\n\
query-source-v6 address *;\n\
recursion true;\n\

View file

@ -13,7 +13,7 @@
<refentry xmlns:db="http://docbook.org/ns/docbook" version="5.0" xml:id="man.named.conf">
<info>
<date>2018-01-22</date>
<date>2018-05-29</date>
</info>
<refentryinfo>
<corpname>ISC</corpname>
@ -205,7 +205,7 @@ options {
<replaceable>integer</replaceable> ] [ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [
port <replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key
<replaceable>string</replaceable> ]; ... } ] [ zone-directory <replaceable>quoted_string</replaceable> ] [
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ]; ... };
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <replaceable>boolean</replaceable>;
check-mx ( fail | warn | ignore );
@ -244,6 +244,7 @@ options {
};
dns64-contact <replaceable>string</replaceable>;
dns64-server <replaceable>string</replaceable>;
dnskey-sig-validity <replaceable>integer</replaceable>;
dnsrps-enable <replaceable>boolean</replaceable>;
dnsrps-options { <replaceable>unspecified-text</replaceable> };
dnssec-accept-expired <replaceable>boolean</replaceable>;
@ -292,14 +293,13 @@ options {
fstrm-set-output-notify-threshold <replaceable>integer</replaceable>;
fstrm-set-output-queue-model ( mpsc | spsc );
fstrm-set-output-queue-size <replaceable>integer</replaceable>;
fstrm-set-reopen-interval <replaceable>integer</replaceable>;
fstrm-set-reopen-interval <replaceable>ttlval</replaceable>;
geoip-directory ( <replaceable>quoted_string</replaceable> | none );
geoip-use-ecs <replaceable>boolean</replaceable>;
glue-cache <replaceable>boolean</replaceable>;
heartbeat-interval <replaceable>integer</replaceable>;
hostname ( <replaceable>quoted_string</replaceable> | none );
inline-signing <replaceable>boolean</replaceable>;
interface-interval <replaceable>integer</replaceable>;
interface-interval <replaceable>ttlval</replaceable>;
ixfr-from-differences ( primary | master | secondary | slave |
<replaceable>boolean</replaceable> );
keep-response-order { <replaceable>address_match_element</replaceable>; ... };
@ -318,10 +318,10 @@ options {
masterfile-style ( full | relative );
match-mapped-addresses <replaceable>boolean</replaceable>;
max-cache-size ( default | unlimited | <replaceable>sizeval</replaceable> | <replaceable>percentage</replaceable> );
max-cache-ttl <replaceable>integer</replaceable>;
max-cache-ttl <replaceable>ttlval</replaceable>;
max-clients-per-query <replaceable>integer</replaceable>;
max-journal-size ( default | unlimited | <replaceable>sizeval</replaceable> );
max-ncache-ttl <replaceable>integer</replaceable>;
max-ncache-ttl <replaceable>ttlval</replaceable>;
max-records <replaceable>integer</replaceable>;
max-recursion-depth <replaceable>integer</replaceable>;
max-recursion-queries <replaceable>integer</replaceable>;
@ -362,6 +362,7 @@ options {
preferred-glue <replaceable>string</replaceable>;
prefetch <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ];
provide-ixfr <replaceable>boolean</replaceable>;
qname-minimization ( strict | relaxed | disabled );
query-source ( ( [ address ] ( <replaceable>ipv4_address</replaceable> | * ) [ port (
<replaceable>integer</replaceable> | * ) ] ) | ( [ [ address ] ( <replaceable>ipv4_address</replaceable> | * ) ]
port ( <replaceable>integer</replaceable> | * ) ) ) [ dscp <replaceable>integer</replaceable> ];
@ -401,18 +402,19 @@ options {
response-padding { <replaceable>address_match_element</replaceable>; ... } block-size
<replaceable>integer</replaceable>;
response-policy { zone <replaceable>quoted_string</replaceable> [ log <replaceable>boolean</replaceable> ] [
max-policy-ttl <replaceable>integer</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ] [
max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ] [
policy ( cname | disabled | drop | given | no-op | nodata |
nxdomain | passthru | tcp-only <replaceable>quoted_string</replaceable> ) ] [
recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
nsdname-enable <replaceable>boolean</replaceable> ]; ... } [ break-dnssec <replaceable>boolean</replaceable> ] [
max-policy-ttl <replaceable>integer</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ] [
max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ] [
min-ns-dots <replaceable>integer</replaceable> ] [ nsip-wait-recurse <replaceable>boolean</replaceable> ] [
qname-wait-recurse <replaceable>boolean</replaceable> ] [ recursive-only <replaceable>boolean</replaceable> ] [
nsip-enable <replaceable>boolean</replaceable> ] [ nsdname-enable <replaceable>boolean</replaceable> ] [
dnsrps-enable <replaceable>boolean</replaceable> ] [ dnsrps-options { <replaceable>unspecified-text</replaceable>
} ];
root-delegation-only [ exclude { <replaceable>quoted_string</replaceable>; ... } ];
root-key-sentinel <replaceable>boolean</replaceable>;
rrset-order { [ class <replaceable>string</replaceable> ] [ type <replaceable>string</replaceable> ] [ name
<replaceable>quoted_string</replaceable> ] <replaceable>string</replaceable> <replaceable>string</replaceable>; ... };
secroots-file <replaceable>quoted_string</replaceable>;
@ -557,7 +559,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
<replaceable>integer</replaceable> ] [ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [
port <replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key
<replaceable>string</replaceable> ]; ... } ] [ zone-directory <replaceable>quoted_string</replaceable> ] [
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ]; ... };
in-memory <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ]; ... };
check-dup-records ( fail | warn | ignore );
check-integrity <replaceable>boolean</replaceable>;
check-mx ( fail | warn | ignore );
@ -595,6 +597,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
};
dns64-contact <replaceable>string</replaceable>;
dns64-server <replaceable>string</replaceable>;
dnskey-sig-validity <replaceable>integer</replaceable>;
dnsrps-enable <replaceable>boolean</replaceable>;
dnsrps-options { <replaceable>unspecified-text</replaceable> };
dnssec-accept-expired <replaceable>boolean</replaceable>;
@ -648,10 +651,10 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
match-destinations { <replaceable>address_match_element</replaceable>; ... };
match-recursive-only <replaceable>boolean</replaceable>;
max-cache-size ( default | unlimited | <replaceable>sizeval</replaceable> | <replaceable>percentage</replaceable> );
max-cache-ttl <replaceable>integer</replaceable>;
max-cache-ttl <replaceable>ttlval</replaceable>;
max-clients-per-query <replaceable>integer</replaceable>;
max-journal-size ( default | unlimited | <replaceable>sizeval</replaceable> );
max-ncache-ttl <replaceable>integer</replaceable>;
max-ncache-ttl <replaceable>ttlval</replaceable>;
max-records <replaceable>integer</replaceable>;
max-recursion-depth <replaceable>integer</replaceable>;
max-recursion-queries <replaceable>integer</replaceable>;
@ -686,6 +689,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
preferred-glue <replaceable>string</replaceable>;
prefetch <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ];
provide-ixfr <replaceable>boolean</replaceable>;
qname-minimization ( strict | relaxed | disabled );
query-source ( ( [ address ] ( <replaceable>ipv4_address</replaceable> | * ) [ port (
<replaceable>integer</replaceable> | * ) ] ) | ( [ [ address ] ( <replaceable>ipv4_address</replaceable> | * ) ]
port ( <replaceable>integer</replaceable> | * ) ) ) [ dscp <replaceable>integer</replaceable> ];
@ -720,18 +724,19 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
response-padding { <replaceable>address_match_element</replaceable>; ... } block-size
<replaceable>integer</replaceable>;
response-policy { zone <replaceable>quoted_string</replaceable> [ log <replaceable>boolean</replaceable> ] [
max-policy-ttl <replaceable>integer</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ] [
max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ] [
policy ( cname | disabled | drop | given | no-op | nodata |
nxdomain | passthru | tcp-only <replaceable>quoted_string</replaceable> ) ] [
recursive-only <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
nsdname-enable <replaceable>boolean</replaceable> ]; ... } [ break-dnssec <replaceable>boolean</replaceable> ] [
max-policy-ttl <replaceable>integer</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ] [
max-policy-ttl <replaceable>ttlval</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ] [
min-ns-dots <replaceable>integer</replaceable> ] [ nsip-wait-recurse <replaceable>boolean</replaceable> ] [
qname-wait-recurse <replaceable>boolean</replaceable> ] [ recursive-only <replaceable>boolean</replaceable> ] [
nsip-enable <replaceable>boolean</replaceable> ] [ nsdname-enable <replaceable>boolean</replaceable> ] [
dnsrps-enable <replaceable>boolean</replaceable> ] [ dnsrps-options { <replaceable>unspecified-text</replaceable>
} ];
root-delegation-only [ exclude { <replaceable>quoted_string</replaceable>; ... } ];
root-key-sentinel <replaceable>boolean</replaceable>;
rrset-order { [ class <replaceable>string</replaceable> ] [ type <replaceable>string</replaceable> ] [ name
<replaceable>quoted_string</replaceable> ] <replaceable>string</replaceable> <replaceable>string</replaceable>; ... };
send-cookie <replaceable>boolean</replaceable>;
@ -824,6 +829,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
dialup ( notify | notify-passive | passive | refresh |
<replaceable>boolean</replaceable> );
dlz <replaceable>string</replaceable>;
dnskey-sig-validity <replaceable>integer</replaceable>;
dnssec-dnskey-kskonly <replaceable>boolean</replaceable>;
dnssec-loadkeys-interval <replaceable>integer</replaceable>;
dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
@ -930,6 +936,7 @@ zone <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
delegation-only <replaceable>boolean</replaceable>;
dialup ( notify | notify-passive | passive | refresh | <replaceable>boolean</replaceable> );
dlz <replaceable>string</replaceable>;
dnskey-sig-validity <replaceable>integer</replaceable>;
dnssec-dnskey-kskonly <replaceable>boolean</replaceable>;
dnssec-loadkeys-interval <replaceable>integer</replaceable>;
dnssec-secure-to-insecure <replaceable>boolean</replaceable>;

View file

@ -3690,6 +3690,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
isc_dscp_t dscp4 = -1, dscp6 = -1;
dns_dyndbctx_t *dctx = NULL;
unsigned int resolver_param;
const char *qminmode = NULL;
REQUIRE(DNS_VIEW_VALID(view));
@ -4639,6 +4640,22 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
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);
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 { /* "disabled" or "off" */
view->qminimization = ISC_FALSE;
view->qmin_strict = ISC_FALSE;
}
obj = NULL;
result = named_config_get(maps, "auth-nxdomain", &obj);
INSIST(result == ISC_R_SUCCESS);

View file

@ -64,7 +64,7 @@ PARALLEL = rpzrecurse serve-stale dnssec \
legacy limits logfileconfig \
masterfile masterformat metadata mkeys \
names notify nslookup nsupdate nzd2nzf \
padding pending pipelined \
padding pending pipelined qmin \
reclimit redirect resolver rndc rootkeysentinel rpz \
rrchecker rrl rrsetorder rsabigexponent runtime \
sfcache smartsign sortlist \

View file

@ -0,0 +1,28 @@
/*
* 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.
*/
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
recursion no;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
notify no;
minimal-responses yes;
};
zone "." {
type master;
file "root.db";
};

View file

@ -0,0 +1,19 @@
; 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.
. IN SOA ns2. hostmaster ( 2 8H 2H 4W 1D);
. NS ns2.
ns1. A 10.53.0.1
ns2. A 10.53.0.2
rt.example. NS ns1.
naptr.example. NS ns1.
rt2.example. NS ns1.
naptr2.example. NS ns1.
nid.example. NS ns1.

View file

@ -7,5 +7,5 @@
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
. NS ns1.
ns1. A 10.53.0.1
. NS ns2.
ns2. A 10.53.0.2

View file

@ -14,4 +14,5 @@ SYSTEMTESTTOP=..
$SHELL clean.sh
copy_setports ns1/named1.conf.in ns1/named.conf
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf

View file

@ -95,7 +95,7 @@ PARALLELDIRS="acl additional addzone allow-query auth autosign \
legacy limits logfileconfig \
masterfile masterformat metadata mkeys \
names notify nslookup nsupdate nzd2nzf \
padding pending pipelined \
padding pending pipelined qmin \
reclimit redirect resolver rndc rootkeysentinel rpz rpzrecurse \
rrchecker rrl rrsetorder rsabigexponent runtime \
serve-stale sfcache smartsign sortlist \

View file

@ -91,8 +91,8 @@ SEQUENTIALDIRS="acl additional addzone autosign builtin \
fetchlimit filter-aaaa formerr forward geoip glue idna inline ixfr \
keepalive @KEYMGR@ legacy limits logfileconfig masterfile \
masterformat metadata mkeys names notify nslookup nsupdate \
nzd2nzf padding pending pipelined @PKCS11_TEST@ reclimit \
redirect resolver rndc rpz rrchecker rrl \
nzd2nzf padding pending pipelined @PKCS11_TEST@ qmin \
reclimit redirect resolver rndc rpz rrchecker rrl \
rrsetorder rsabigexponent runtime sfcache smartsign sortlist \
spf staticstub statistics statschannel stub tcp tkey tsig \
tsiggss unknown upforwd verify views wildcard xfer xferquota \

0
bin/tests/system/ifconfig.sh Normal file → Executable file
View file

221
bin/tests/system/qmin/ans2/ans.py Executable file
View file

@ -0,0 +1,221 @@
############################################################################
# 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
# 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
#
# 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.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) 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.2)
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

175
bin/tests/system/qmin/ans3/ans.py Executable file
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

175
bin/tests/system/qmin/ans4/ans.py Executable file
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

@ -0,0 +1,18 @@
#!/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 ans*/query.log
rm -f query*.log

View file

@ -0,0 +1,30 @@
/*
* 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;
dnssec-validation no;
};
zone "." {
type master;
file "root.db";
};

View file

@ -0,0 +1,32 @@
; 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

View file

@ -0,0 +1,41 @@
/*
* 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 disabled;
querylog yes;
resolver-query-timeout 30;
dnssec-validation no;
};
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";
};

View file

@ -0,0 +1,41 @@
/*
* 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.
*/
// NS6
options {
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.6; };
listen-on-v6 { none; };
recursion yes;
qname-minimization strict;
querylog yes;
resolver-query-timeout 30;
dnssec-validation no;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../common/root.hint";
};

View file

@ -0,0 +1,41 @@
/*
* 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.
*/
// NS7
options {
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.7; };
listen-on-v6 { none; };
recursion yes;
qname-minimization relaxed;
querylog yes;
resolver-query-timeout 30;
dnssec-validation no;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../common/root.hint";
};

View file

@ -0,0 +1,29 @@
#!/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
$SHELL ../testcrypto.sh || exit 255
if test -n "$PYTHON"
then
if $PYTHON -c "import dns" 2> /dev/null
then
:
else
echo_i "This test requires the dnspython module." >&2
exit 1
fi
else
echo_i "This test requires Python and the dnspython module." >&2
exit 1
fi

View file

@ -0,0 +1,20 @@
#!/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 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

279
bin/tests/system/qmin/tests.sh Executable file
View file

@ -0,0 +1,279 @@
#!/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 ans*/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.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
grep "icky.icky.icky.ptang.zoop.boing.good. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
sleep 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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.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
grep "icky.icky.icky.ptang.zoop.boing.bad. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
sleep 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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.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
grep "icky.icky.icky.ptang.zoop.boing.slow. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || ret=1
sleep 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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.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
sleep 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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 in strict mode ($n)"
ret=0
$CLEANQL
$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
sleep 1
echo "NS boing.bad." | diff ans2/query.log - > /dev/null || ret=1
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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 in relaxed mode ($n)"
ret=0
$CLEANQL
$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
sleep 1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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.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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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 proper boundaries when qname-minimization is on ($n)"
ret=0
$CLEANQL
$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
sleep 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
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
sleep 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
sleep 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
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View file

@ -19,6 +19,7 @@ options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
servfail-ttl 0;
qname-minimization disabled;
max-recursion-depth 12;
recursion yes;
dnssec-validation yes;

View file

@ -19,6 +19,7 @@ options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
servfail-ttl 0;
qname-minimization disabled;
max-recursion-depth 5;
recursion yes;
dnssec-validation yes;

View file

@ -19,6 +19,7 @@ options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
servfail-ttl 0;
qname-minimization disabled;
max-recursion-depth 100;
max-recursion-queries 50;
recursion yes;

View file

@ -19,6 +19,7 @@ options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
servfail-ttl 0;
qname-minimization disabled;
max-recursion-depth 100;
max-recursion-queries 40;
recursion yes;

View file

@ -57,7 +57,13 @@ for (;;) {
my $qname = $questions[0]->qname;
my $qtype = $questions[0]->qtype;
if ($qname eq "cname1.example.com") {
if ($qname eq "com" && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("com 300 NS a.root-servers.nil."));
} elsif ($qname eq "example.com" && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("example.com 300 NS a.root-servers.nil."));
} elsif ($qname eq "cname1.example.com") {
# Data for the "cname + other data / 1" test
$packet->push("answer", new Net::DNS::RR("cname1.example.com 300 CNAME cname1.example.com"));
$packet->push("answer", new Net::DNS::RR("cname1.example.com 300 A 1.2.3.4"));
@ -65,6 +71,15 @@ for (;;) {
# Data for the "cname + other data / 2" test: same RRs in opposite order
$packet->push("answer", new Net::DNS::RR("cname2.example.com 300 A 1.2.3.4"));
$packet->push("answer", new Net::DNS::RR("cname2.example.com 300 CNAME cname2.example.com"));
} elsif ($qname eq "org" && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("org 300 NS a.root-servers.nil."));
} elsif ($qname eq "example.org" && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("example.org 300 NS a.root-servers.nil."));
} elsif (($qname eq "baddname.example.org" || $qname eq "gooddname.example.org") && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("example.org 300 NS a.root-servers.nil."));
} elsif ($qname eq "www.example.org" || $qname eq "www.example.net" ||
$qname eq "badcname.example.org" ||
$qname eq "goodcname.example.org" ||
@ -81,6 +96,12 @@ for (;;) {
new Net::DNS::RR($qname .
" 300 AAAA 2001:db8:beef::1"));
}
} elsif ($qname eq "net" && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("net 300 NS a.root-servers.nil."));
} elsif ($qname eq "example.net" && $qtype eq "NS") {
$packet->header->aa(1);
$packet->push("answer", new Net::DNS::RR("example.net 300 NS a.root-servers.nil."));
} elsif ($qname eq "badcname.example.net" ||
$qname eq "goodcname.example.net") {
# Data for CNAME/DNAME filtering. We need to make one-level
@ -97,7 +118,7 @@ for (;;) {
# expected to be accepted regardless of the filter setting.
$packet->push("authority", new Net::DNS::RR("sub.example.org 300 NS ns.sub.example.org"));
$packet->push("additional", new Net::DNS::RR("ns.sub.example.org 300 A 10.53.0.3"));
} elsif ($qname =~ /\.broken/) {
} elsif ($qname =~ /\.broken/ || $qname =~ /^broken/) {
# Delegation to broken TLD.
$packet->push("authority", new Net::DNS::RR("broken 300 NS ns.broken"));
$packet->push("additional", new Net::DNS::RR("ns.broken 300 A 10.53.0.4"));

View file

@ -61,6 +61,8 @@ for (;;) {
$packet->push("answer",
new Net::DNS::RR($qname .
" 300 CNAME badcname.example.org"));
} elsif (($qname eq "baddname.example.net" || $qname eq "gooddname.example.net") && $qtype eq "NS") {
$packet->push("authority", new Net::DNS::RR("example.net IN SOA (1 2 3 4 5)"))
} elsif ($qname eq "foo.baddname.example.net") {
$packet->push("answer",
new Net::DNS::RR("baddname.example.net" .

0
bin/tests/system/run.sh Normal file → Executable file
View file

0
bin/tests/system/runall.sh Normal file → Executable file
View file

0
bin/tests/system/runsequential.sh Normal file → Executable file
View file

View file

@ -21,6 +21,7 @@ options {
recursion yes;
dnssec-validation yes;
notify yes;
qname-minimization disabled;
};
statistics-channels {

0
bin/tests/system/testsock.pl Normal file → Executable file
View file

30
configure vendored
View file

@ -936,6 +936,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -1094,6 +1095,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -1346,6 +1348,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1483,7 +1494,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1636,6 +1647,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -12208,6 +12220,9 @@ except: exit(1)'
testply='try: from ply import *
except: exit(1)'
testdnspython='try: import dns.message
except: exit(1)'
testminvers='import sys
if (sys.version_info < (2,7)) or (sys.version_info < (3,2) and sys.version_info >= (3,0)):
exit(1)'
@ -12301,6 +12316,19 @@ $as_echo "not found" >&6; }
$as_echo_n "checking python module 'ply'... " >&6; }
if ${PYTHON:-false} -c "$testply"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
$as_echo "found" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
$as_echo "not found" >&6; }
unset ac_cv_path_PYTHON
unset PYTHON
continue
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking python module 'dnspython'" >&5
$as_echo_n "checking python module 'dnspython'... " >&6; }
if ${PYTHON:-false} -c "$testdnspython"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
$as_echo "found" >&6; }
break
else

View file

@ -185,6 +185,9 @@ except: exit(1)'
testply='try: from ply import *
except: exit(1)'
testdnspython='try: import dns.message
except: exit(1)'
testminvers='import sys
if (sys.version_info < (2,7)) or (sys.version_info < (3,2) and sys.version_info >= (3,0)):
exit(1)'
@ -225,6 +228,16 @@ case "$use_python" in
AC_MSG_CHECKING([python module 'ply'])
if ${PYTHON:-false} -c "$testply"; then
AC_MSG_RESULT([found])
else
AC_MSG_RESULT([not found])
unset ac_cv_path_PYTHON
unset PYTHON
continue
fi
AC_MSG_CHECKING([python module 'dnspython'])
if ${PYTHON:-false} -c "$testdnspython"; then
AC_MSG_RESULT([found])
break
else
AC_MSG_RESULT([not found])

View file

@ -4665,6 +4665,26 @@ badresp:1,adberr:0,findfail:0,valfail:0]
</listitem>
</varlistentry>
<varlistentry>
<term><command>qname-minimization</command></term>
<listitem>
<para>
This option controls QNAME minimization behaviour
in the BIND resolver. When set to <command>strict</command>,
BIND will follow the QNAME minimization algorithm to
the letter, as specified in RFC 7816. Setting this
option to <command>relaxed</command> will cause BIND
to fall back to normal (non-minimized) query mode
when it receives either NXDOMAIN or other unexpected
responses (e.g. SERVFAIL, improper zone cut, REFUSED)
to a minimized query. <command>disabled</command> disables
QNAME minimization completely. The current default is
<command>relaxed</command>, but it might be changed to
<command>strict</command> in a future release.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>tkey-gssapi-keytab</command></term>
<listitem>

View file

@ -33,6 +33,7 @@
<command>database</command> <replaceable>string</replaceable>;
<command>dialup</command> ( notify | notify-passive | passive | refresh | <replaceable>boolean</replaceable> );
<command>dlz</command> <replaceable>string</replaceable>;
<command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
<command>dnssec-dnskey-kskonly</command> <replaceable>boolean</replaceable>;
<command>dnssec-loadkeys-interval</command> <replaceable>integer</replaceable>;
<command>dnssec-secure-to-insecure</command> <replaceable>boolean</replaceable>;

View file

@ -99,6 +99,15 @@
signatures covering DNSKEY RRsets. [GL #145]
</para>
</listitem>
<listitem>
<para>
Support for QNAME minimization was added and enabled by default
in <command>relaxed</command> mode, in which BIND will fall back
to normal resolution if the remote server returns something
unexpected during the query minimization process. This default
setting might change to <command>strict</command> in the future.
</para>
</listitem>
</itemizedlist>
</section>

View file

@ -44,7 +44,7 @@
<replaceable>integer</replaceable> ] [ dscp <replaceable>integer</replaceable> ] { ( <replaceable>masters</replaceable> | <replaceable>ipv4_address</replaceable> [
<command>port</command> <replaceable>integer</replaceable> ] | <replaceable>ipv6_address</replaceable> [ port <replaceable>integer</replaceable> ] ) [ key
<replaceable>string</replaceable> ]; ... } ] [ zone-directory <replaceable>quoted_string</replaceable> ] [
<command>in-memory</command> <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ]; ... };
<command>in-memory</command> <replaceable>boolean</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ]; ... };
<command>check-dup-records</command> ( fail | warn | ignore );
<command>check-integrity</command> <replaceable>boolean</replaceable>;
<command>check-mx</command> ( fail | warn | ignore );
@ -83,6 +83,7 @@
};
<command>dns64-contact</command> <replaceable>string</replaceable>;
<command>dns64-server</command> <replaceable>string</replaceable>;
<command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
<command>dnsrps-enable</command> <replaceable>boolean</replaceable>;
<command>dnsrps-options</command> { <replaceable>unspecified-text</replaceable> };
<command>dnssec-accept-expired</command> <replaceable>boolean</replaceable>;
@ -131,14 +132,13 @@
<command>fstrm-set-output-notify-threshold</command> <replaceable>integer</replaceable>;
<command>fstrm-set-output-queue-model</command> ( mpsc | spsc );
<command>fstrm-set-output-queue-size</command> <replaceable>integer</replaceable>;
<command>fstrm-set-reopen-interval</command> <replaceable>integer</replaceable>;
<command>fstrm-set-reopen-interval</command> <replaceable>ttlval</replaceable>;
<command>geoip-directory</command> ( <replaceable>quoted_string</replaceable> | none );
<command>geoip-use-ecs</command> <replaceable>boolean</replaceable>;
<command>glue-cache</command> <replaceable>boolean</replaceable>;
<command>heartbeat-interval</command> <replaceable>integer</replaceable>;
<command>hostname</command> ( <replaceable>quoted_string</replaceable> | none );
<command>inline-signing</command> <replaceable>boolean</replaceable>;
<command>interface-interval</command> <replaceable>integer</replaceable>;
<command>interface-interval</command> <replaceable>ttlval</replaceable>;
<command>ixfr-from-differences</command> ( primary | master | secondary | slave |
<replaceable>boolean</replaceable> );
<command>keep-response-order</command> { <replaceable>address_match_element</replaceable>; ... };
@ -157,10 +157,10 @@
<command>masterfile-style</command> ( full | relative );
<command>match-mapped-addresses</command> <replaceable>boolean</replaceable>;
<command>max-cache-size</command> ( default | unlimited | <replaceable>sizeval</replaceable> | <replaceable>percentage</replaceable> );
<command>max-cache-ttl</command> <replaceable>integer</replaceable>;
<command>max-cache-ttl</command> <replaceable>ttlval</replaceable>;
<command>max-clients-per-query</command> <replaceable>integer</replaceable>;
<command>max-journal-size</command> ( default | unlimited | <replaceable>sizeval</replaceable> );
<command>max-ncache-ttl</command> <replaceable>integer</replaceable>;
<command>max-ncache-ttl</command> <replaceable>ttlval</replaceable>;
<command>max-records</command> <replaceable>integer</replaceable>;
<command>max-recursion-depth</command> <replaceable>integer</replaceable>;
<command>max-recursion-queries</command> <replaceable>integer</replaceable>;
@ -201,6 +201,7 @@
<command>preferred-glue</command> <replaceable>string</replaceable>;
<command>prefetch</command> <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ];
<command>provide-ixfr</command> <replaceable>boolean</replaceable>;
<command>qname-minimization</command> ( strict | relaxed | disabled );
<command>query-source</command> ( ( [ address ] ( <replaceable>ipv4_address</replaceable> | * ) [ port (
<replaceable>integer</replaceable> | * ) ] ) | ( [ [ address ] ( <replaceable>ipv4_address</replaceable> | * ) ]
<command>port</command> ( <replaceable>integer</replaceable> | * ) ) ) [ dscp <replaceable>integer</replaceable> ];
@ -240,18 +241,19 @@
<command>response-padding</command> { <replaceable>address_match_element</replaceable>; ... } block-size
<replaceable>integer</replaceable>;
<command>response-policy</command> { zone <replaceable>quoted_string</replaceable> [ log <replaceable>boolean</replaceable> ] [
<command>max-policy-ttl</command> <replaceable>integer</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ] [
<command>max-policy-ttl</command> <replaceable>ttlval</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ] [
<command>policy</command> ( cname | disabled | drop | given | no-op | nodata |
<command>nxdomain</command> | passthru | tcp-only <replaceable>quoted_string</replaceable> ) ] [
<command>recursive-only</command> <replaceable>boolean</replaceable> ] [ nsip-enable <replaceable>boolean</replaceable> ] [
<command>nsdname-enable</command> <replaceable>boolean</replaceable> ]; ... } [ break-dnssec <replaceable>boolean</replaceable> ] [
<command>max-policy-ttl</command> <replaceable>integer</replaceable> ] [ min-update-interval <replaceable>integer</replaceable> ] [
<command>max-policy-ttl</command> <replaceable>ttlval</replaceable> ] [ min-update-interval <replaceable>ttlval</replaceable> ] [
<command>min-ns-dots</command> <replaceable>integer</replaceable> ] [ nsip-wait-recurse <replaceable>boolean</replaceable> ] [
<command>qname-wait-recurse</command> <replaceable>boolean</replaceable> ] [ recursive-only <replaceable>boolean</replaceable> ] [
<command>nsip-enable</command> <replaceable>boolean</replaceable> ] [ nsdname-enable <replaceable>boolean</replaceable> ] [
<command>dnsrps-enable</command> <replaceable>boolean</replaceable> ] [ dnsrps-options { <replaceable>unspecified-text</replaceable>
} ];
<command>root-delegation-only</command> [ exclude { <replaceable>quoted_string</replaceable>; ... } ];
<command>root-key-sentinel</command> <replaceable>boolean</replaceable>;
<command>rrset-order</command> { [ class <replaceable>string</replaceable> ] [ type <replaceable>string</replaceable> ] [ name
<replaceable>quoted_string</replaceable> ] <replaceable>string</replaceable> <replaceable>string</replaceable>; ... };
<command>secroots-file</command> <replaceable>quoted_string</replaceable>;

View file

@ -26,6 +26,7 @@
<command>database</command> <replaceable>string</replaceable>;
<command>dialup</command> ( notify | notify-passive | passive | refresh | <replaceable>boolean</replaceable> );
<command>dlz</command> <replaceable>string</replaceable>;
<command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
<command>dnssec-dnskey-kskonly</command> <replaceable>boolean</replaceable>;
<command>dnssec-loadkeys-interval</command> <replaceable>integer</replaceable>;
<command>dnssec-update-mode</command> ( maintain | no-resign );

View file

@ -185,7 +185,7 @@ options {
fstrm-set-output-queue-size <integer>; // not configured
fstrm-set-reopen-interval <ttlval>; // not configured
geoip-directory ( <quoted_string> | none ); // not configured
geoip-use-ecs <boolean>; // not configured
geoip-use-ecs <boolean>; // obsolete
glue-cache <boolean>;
has-old-clients <boolean>; // obsolete
heartbeat-interval <integer>;
@ -205,7 +205,7 @@ options {
listen-on-v6 [ port <integer> ] [ dscp
<integer> ] {
<address_match_element>; ... }; // may occur multiple times
lmdb-mapsize <sizeval>; // non-operational
lmdb-mapsize <sizeval>;
lock-file ( <quoted_string> | none );
maintain-ixfr-base <boolean>; // obsolete
managed-keys-directory <quoted_string>;
@ -264,6 +264,7 @@ options {
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
qname-minimization ( strict | relaxed | disabled );
query-source ( ( [ address ] ( <ipv4_address> | * ) [ port (
<integer> | * ) ] ) | ( [ [ address ] ( <ipv4_address> | * ) ]
port ( <integer> | * ) ) ) [ dscp <integer> ];
@ -543,7 +544,7 @@ view <string> [ <class> ] {
}; // may occur multiple times
key-directory <quoted_string>;
lame-ttl <ttlval>;
lmdb-mapsize <sizeval>; // non-operational
lmdb-mapsize <sizeval>;
maintain-ixfr-base <boolean>; // obsolete
managed-keys { <string> <string>
<integer> <integer> <integer>
@ -597,6 +598,7 @@ view <string> [ <class> ] {
preferred-glue <string>;
prefetch <integer> [ <integer> ];
provide-ixfr <boolean>;
qname-minimization ( strict | relaxed | disabled );
query-source ( ( [ address ] ( <ipv4_address> | * ) [ port (
<integer> | * ) ] ) | ( [ [ address ] ( <ipv4_address> | * ) ]
port ( <integer> | * ) ) ) [ dscp <integer> ];

View file

@ -4030,6 +4030,14 @@ fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
options |= DNS_FETCHOPT_UNSHARED;
}
if (adb->view->qminimization) {
options |= DNS_FETCHOPT_QMINIMIZE;
options |= DNS_FETCHOPT_QMIN_SKIP_IP6A;
if (adb->view->qmin_strict) {
options |= DNS_FETCHOPT_QMIN_STRICT;
}
}
fetch = new_adbfetch(adb);
if (fetch == NULL) {
result = ISC_R_NOMEMORY;

View file

@ -88,23 +88,33 @@ typedef enum {
/*
* Options that modify how a 'fetch' is done.
*/
#define DNS_FETCHOPT_TCP 0x0001 /*%< Use TCP. */
#define DNS_FETCHOPT_UNSHARED 0x0002 /*%< See below. */
#define DNS_FETCHOPT_RECURSIVE 0x0004 /*%< Set RD? */
#define DNS_FETCHOPT_NOEDNS0 0x0008 /*%< Do not use EDNS. */
#define DNS_FETCHOPT_FORWARDONLY 0x0010 /*%< Only use forwarders. */
#define DNS_FETCHOPT_NOVALIDATE 0x0020 /*%< Disable validation. */
#define DNS_FETCHOPT_EDNS512 0x0040 /*%< Advertise a 512 byte
UDP buffer. */
#define DNS_FETCHOPT_WANTNSID 0x0080 /*%< Request NSID */
#define DNS_FETCHOPT_PREFETCH 0x0100 /*%< Do prefetch */
#define DNS_FETCHOPT_NOCDFLAG 0x0200 /*%< Don't set CD flag. */
#define DNS_FETCHOPT_NONTA 0x0400 /*%< Ignore NTA table. */
/* RESERVED ECS 0x0000 */
/* RESERVED ECS 0x1000 */
/* RESERVED ECS 0x2000 */
/* RESERVED TCPCLIENT 0x4000 */
#define DNS_FETCHOPT_NOCACHED 0x8000 /*%< Force cache update. */
#define DNS_FETCHOPT_TCP 0x00000001 /*%< Use TCP. */
#define DNS_FETCHOPT_UNSHARED 0x00000002 /*%< See below. */
#define DNS_FETCHOPT_RECURSIVE 0x00000004 /*%< Set RD? */
#define DNS_FETCHOPT_NOEDNS0 0x00000008 /*%< Do not use EDNS. */
#define DNS_FETCHOPT_FORWARDONLY 0x00000010 /*%< Only use forwarders. */
#define DNS_FETCHOPT_NOVALIDATE 0x00000020 /*%< Disable validation. */
#define DNS_FETCHOPT_EDNS512 0x00000040 /*%< Advertise a 512 byte
UDP buffer. */
#define DNS_FETCHOPT_WANTNSID 0x00000080 /*%< Request NSID */
#define DNS_FETCHOPT_PREFETCH 0x00000100 /*%< Do prefetch */
#define DNS_FETCHOPT_NOCDFLAG 0x00000200 /*%< Don't set CD flag. */
#define DNS_FETCHOPT_NONTA 0x00000400 /*%< Ignore NTA table. */
/* RESERVED ECS 0x00000000 */
/* RESERVED ECS 0x00001000 */
/* RESERVED ECS 0x00002000 */
/* RESERVED TCPCLIENT 0x00004000 */
#define DNS_FETCHOPT_NOCACHED 0x00008000 /*%< 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_IP6A 0x00040000 /*%< Skip some labels
when doing qname
minimization on
ip6.arpa. */
/* Reserved in use by adb.c 0x00400000 */
#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000
@ -134,6 +144,10 @@ typedef enum {
#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,
@ -267,7 +281,7 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
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,

View file

@ -115,6 +115,8 @@ struct dns_view {
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;

View file

@ -258,13 +258,14 @@ struct fetchctx {
/*% 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;
char * info;
isc_mem_t * mctx;
isc_stdtime_t now;
/*% Locked by appropriate bucket lock. */
fetchstate state;
@ -275,6 +276,7 @@ struct fetchctx {
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;
@ -304,6 +306,12 @@ struct fetchctx {
isc_boolean_t ns_ttl_ok;
isc_uint32_t ns_ttl;
isc_counter_t * qc;
isc_boolean_t minimized;
unsigned int qmin_labels;
unsigned int qmin_steps;
isc_boolean_t ip6arpaskip;
dns_name_t name;
dns_rdatatype_t type;
/*%
* The number of events we're waiting for.
@ -554,6 +562,11 @@ void dns_resolver_setfuzzing() {
}
#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);
@ -561,6 +574,7 @@ static void resquery_response(isc_task_t *task, isc_event_t *event);
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,
@ -677,7 +691,7 @@ typedef struct respctx {
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;
@ -749,6 +763,12 @@ rctx_referral(respctx_t *rctx);
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);
@ -2524,8 +2544,8 @@ resquery_send(resquery_t *query) {
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) {
@ -2954,7 +2974,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
FCTXTRACE("query canceled: "
"resquery_send() failed; responding");
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE, ISC_FALSE);
fctx_cancelquery(&query, NULL, NULL,
ISC_FALSE, ISC_FALSE);
fctx_done(fctx, result, __LINE__);
}
break;
@ -2973,7 +2994,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
* No route to remote.
*/
isc_socket_detach(&query->tcpsocket);
fctx_cancelquery(&query, NULL, NULL, ISC_TRUE, ISC_FALSE);
fctx_cancelquery(&query, NULL, NULL,
ISC_TRUE, ISC_FALSE);
retry = ISC_TRUE;
break;
@ -2983,7 +3005,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
sevent->result);
isc_socket_detach(&query->tcpsocket);
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE, ISC_FALSE);
fctx_cancelquery(&query, NULL, NULL,
ISC_FALSE, ISC_FALSE);
break;
}
}
@ -3097,8 +3120,9 @@ mark_bad(fetchctx_t *fctx) {
isc_boolean_t all_bad = ISC_TRUE;
#ifdef ENABLE_AFL
if (dns_fuzzing_resolver)
return ISC_FALSE;
if (dns_fuzzing_resolver) {
return (ISC_FALSE);
}
#endif
/*
@ -4136,6 +4160,7 @@ fctx_destroy(fetchctx_t *fctx) {
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);
@ -4418,7 +4443,7 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client,
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;
@ -4514,9 +4539,14 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
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;
/*
@ -4532,6 +4562,11 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
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;
fctx->qmin_steps = 0;
isc_stdtime_get(&fctx->now);
ISC_LIST_INIT(fctx->queries);
ISC_LIST_INIT(fctx->finds);
ISC_LIST_INIT(fctx->altfinds);
@ -4635,12 +4670,12 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
*/
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;
@ -4726,6 +4761,17 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
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) != 0) {
fctx->ip6arpaskip =
ISC_TF((options & DNS_FETCHOPT_QMIN_SKIP_IP6A) != 0 &&
dns_name_issubdomain(&fctx->name, &ip6_arpa));
fctx_minimize_qname(fctx);
}
ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
LOCK(&res->nlock);
@ -4754,6 +4800,9 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
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);
@ -5636,6 +5685,8 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
unsigned int valoptions = 0;
isc_boolean_t checknta = ISC_TRUE;
FCTXTRACE("cache_name");
/*
* The appropriate bucket lock must be held.
*/
@ -6459,12 +6510,10 @@ check_related(void *arg, const dns_name_t *addname, dns_rdatatype_t type) {
#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,
@ -7384,7 +7433,6 @@ rctx_respinit(isc_task_t *task, dns_dispatchevent_t *devent,
TIME_NOW(&rctx->tnow);
rctx->finish = &rctx->tnow;
isc_stdtime_get(&rctx->now);
}
/*
@ -7752,7 +7800,12 @@ rctx_answer(respctx_t *rctx) {
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);
@ -8453,7 +8506,19 @@ rctx_answer_none(respctx_t *rctx) {
} 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.
*/
if (fctx->minimized &&
(fctx->options & DNS_FETCHOPT_QMIN_STRICT) == 0) {
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);
}
@ -8475,6 +8540,21 @@ rctx_answer_none(respctx_t *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) {
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.
@ -8842,6 +8922,10 @@ rctx_referral(respctx_t *rctx) {
check_answer, fctx);
}
#endif
if (fctx->minimized) {
(void)dns_rdataset_additionaldata(rctx->ns_rdataset,
check_answer, fctx);
}
fctx->attributes &= ~FCTX_ATTR_GLUING;
/*
@ -8887,6 +8971,39 @@ rctx_referral(respctx_t *rctx) {
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
@ -8903,8 +9020,6 @@ rctx_referral(respctx_t *rctx) {
rctx->fctx->neterr = 0;
rctx->fctx->badresp = 0;
rctx->fctx->adberr = 0;
return (ISC_R_COMPLETE);
}
/*
@ -8990,7 +9105,7 @@ rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
}
result = dns_view_findzonecut(fctx->res->view,
name, fname,
rctx->now, findoptions,
fctx->now, findoptions,
ISC_TRUE, ISC_TRUE,
&fctx->nameservers,
NULL);
@ -9282,15 +9397,27 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) {
}
/*
* Some servers do not ignore unknown EDNS options.
* If we're minimizing in relaxed mode try to disable minimization.
*/
if (!NOCOOKIE(query->addrinfo) &&
if (fctx->minimized &&
(fctx->options & DNS_FETCHOPT_QMIN_STRICT) == 0)
{
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
"disabling qname minimization for '%s'"
" due to bad server", fctx->info);
fctx->qmin_labels = DNS_MAX_LABELS + 1;
result = rctx_answer_minimized(rctx);
} else if (!NOCOOKIE(query->addrinfo) &&
(fctx->rmessage->rcode == dns_rcode_formerr ||
fctx->rmessage->rcode == dns_rcode_notimp ||
fctx->rmessage->rcode == dns_rcode_refused) &&
dns_adb_getcookie(fctx->adb, query->addrinfo,
cookie, sizeof(cookie)) == 0U)
{
/*
* Some servers do not ignore unknown EDNS options.
*/
dns_adb_changeflags(fctx->adb, query->addrinfo,
FCTX_ADDRINFO_NOCOOKIE,
FCTX_ADDRINFO_NOCOOKIE);
@ -10138,9 +10265,9 @@ fctx_match(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type,
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
@ -10164,6 +10291,67 @@ log_fetch(const dns_name_t *name, dns_rdatatype_t type) {
"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;
}
} 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) {
/*
* 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;
fctx->qmin_steps++;
} 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,
@ -10428,7 +10616,8 @@ dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx,
"%06" ISC_PRINT_QUADFORMAT "u: %s/%s "
"[domain:%s,referral:%u,restart:%u,qrysent:%u,"
"timeout:%u,lame:%u,quota:%u,neterr:%u,"
"badresp:%u,adberr:%u,findfail:%u,valfail:%u]",
"badresp:%u,adberr:%u,findfail:%u,valfail:%u,"
"qminsteps:%u]",
__FILE__, fctx->exitline, fctx->info,
fctx->duration / US_PER_SEC,
fctx->duration % US_PER_SEC,
@ -10438,7 +10627,8 @@ dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx,
fctx->querysent, fctx->timeouts,
fctx->lamecount, fctx->quotacount,
fctx->neterr, fctx->badresp, fctx->adberr,
fctx->findfail, fctx->valfail);
fctx->findfail, fctx->valfail,
fctx->qmin_steps);
fctx->logged = ISC_TRUE;
}

View file

@ -182,6 +182,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
* 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;

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_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;
@ -1937,6 +1938,7 @@ view_clauses[] = {
{ "preferred-glue", &cfg_type_astring, 0 },
{ "prefetch", &cfg_type_prefetch, 0 },
{ "provide-ixfr", &cfg_type_boolean, 0 },
{ "qname-minimization", &cfg_type_qminmethod, 0 },
/*
* Note that the query-source option syntax is different
* from the other -source options.
@ -2949,6 +2951,15 @@ static cfg_type_t cfg_type_optional_keyref = {
doc_optional_keyvalue, &cfg_rep_string, &key_kw
};
static const char *qminmethod_enums[] = {
"strict", "relaxed", "disabled", "off", 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:

View file

@ -11106,6 +11106,14 @@ ns_query_start(ns_client_t *client) {
} 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_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.

View file

@ -433,6 +433,8 @@
./bin/tests/system/additional/ns1/rt.db ZONE 2013,2016,2018
./bin/tests/system/additional/ns1/rt2.db ZONE 2013,2016,2018
./bin/tests/system/additional/ns1/srv.db ZONE 2016,2018
./bin/tests/system/additional/ns2/named.conf.in CONF-C 2018
./bin/tests/system/additional/ns2/root.db ZONE 2018
./bin/tests/system/additional/ns3/named.conf.in CONF-C 2017,2018
./bin/tests/system/additional/ns3/root.hint ZONE 2017,2018
./bin/tests/system/additional/setup.sh SH 2013,2016,2018
@ -1729,6 +1731,18 @@
./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/qmin/ans2/ans.py PYTHON 2018
./bin/tests/system/qmin/ans3/ans.py PYTHON 2018
./bin/tests/system/qmin/ans4/ans.py PYTHON 2018
./bin/tests/system/qmin/clean.sh SH 2018
./bin/tests/system/qmin/ns1/named.conf.in CONF-C 2018
./bin/tests/system/qmin/ns1/root.db ZONE 2018
./bin/tests/system/qmin/ns5/named.conf.in CONF-C 2018
./bin/tests/system/qmin/ns6/named.conf.in CONF-C 2018
./bin/tests/system/qmin/ns7/named.conf.in CONF-C 2018
./bin/tests/system/qmin/prereq.sh SH 2018
./bin/tests/system/qmin/setup.sh SH 2018
./bin/tests/system/qmin/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