QNAME miminimization should create a separate fetch context for each fetch -

this makes the cache more efficient and eliminates duplicates queries.
This commit is contained in:
Witold Kręcicki 2018-06-13 09:29:40 +02:00
parent 36e431d632
commit 70a1ba20ec
26 changed files with 456 additions and 255 deletions

View file

@ -771,7 +771,7 @@ main(int argc, char *argv[]) {
if (noexact_zonecut)
zcoptions |= DNS_DBFIND_NOEXACT;
result = dns_db_findzonecut(db, &name, zcoptions,
0, &node, fname,
0, &node, fname, NULL,
&rdataset, &sigrdataset);
} else {
result = dns_db_find(db, &name, version, type,

View file

@ -220,14 +220,15 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
static isc_result_t
findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
dns_name_t *dcname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
{
sampledb_t *sampledb = (sampledb_t *) db;
REQUIRE(VALID_SAMPLEDB(sampledb));
return (dns_db_findzonecut(sampledb->rbtdb, name, options,
now, nodep, foundname, rdataset,
now, nodep, foundname, dcname, rdataset,
sigrdataset));
}

View file

@ -19,7 +19,7 @@ from datetime import datetime, timedelta
import time
import functools
import dns, dns.message, dns.query
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
@ -44,6 +44,8 @@ def logquery(type, qname):
#
# For bad. it works the same as for good., but returns NXDOMAIN to non-empty terminals
#
# For ugly. it works the same as for good., but returns garbage 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
@ -61,6 +63,7 @@ def create_response(msg):
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
ugly = False
slow = False
# log this query
@ -76,9 +79,11 @@ def create_response(msg):
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."))
r.flags |= dns.flags.AA
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."))
r.flags |= dns.flags.AA
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"))
@ -91,6 +96,7 @@ def create_response(msg):
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."))
r.flags |= dns.flags.AA
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"))
@ -103,6 +109,10 @@ def create_response(msg):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif lqname.endswith("ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif lqname.endswith("good."):
suffix = "good."
lqname = lqname[:-5]
@ -114,25 +124,33 @@ def create_response(msg):
r.set_rcode(REFUSED)
return r
# Good/bad differs only in how we treat non-empty terminals
# Good/bad/ugly 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"))
r.flags |= dns.flags.AA
elif lqname == "" and rrtype == NS:
r.answer.append(dns.rrset.from_text(suffix, 1, IN, NS, "ns2." + suffix))
r.flags |= dns.flags.AA
elif lqname == "ns2." and rrtype == A:
r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, A, "10.53.0.2"))
r.flags |= dns.flags.AA
elif lqname == "ns2." and rrtype == AAAA:
r.answer.append(dns.rrset.from_text("ns2."+suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::2"))
r.flags |= dns.flags.AA
elif lqname == "ns3." and rrtype == A:
r.answer.append(dns.rrset.from_text("ns3."+suffix, 1, IN, A, "10.53.0.3"))
r.flags |= dns.flags.AA
elif lqname == "ns3." and rrtype == AAAA:
r.answer.append(dns.rrset.from_text("ns3."+suffix, 1, IN, AAAA, "fd92:7065:b8e:ffff::3"))
r.flags |= dns.flags.AA
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"))
r.flags |= dns.flags.AA
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"))
r.flags |= dns.flags.AA
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 \
@ -140,6 +158,8 @@ def create_response(msg):
"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 ugly:
r.set_rcode(FORMERR)
if slow:
time.sleep(0.2)
return r

View file

@ -19,7 +19,7 @@ from datetime import datetime, timedelta
import time
import functools
import dns, dns.message, dns.query
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
@ -41,6 +41,8 @@ def logquery(type, qname):
# 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 ugly. it works the same as for good., but returns garbage to non-empty terminals
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
@ -54,6 +56,7 @@ def create_response(msg):
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
ugly = False
slow = False
# log this query
@ -68,6 +71,10 @@ def create_response(msg):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif lqname.endswith("ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif lqname.endswith("good."):
suffix = "good."
lqname = lqname[:-5]
@ -82,12 +89,15 @@ def create_response(msg):
# 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))
r.flags |= dns.flags.AA
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)
if ugly:
r.set_rcode(FORMERR)
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)

View file

@ -19,7 +19,7 @@ from datetime import datetime, timedelta
import time
import functools
import dns, dns.message, dns.query
import dns, dns.message, dns.query, dns.flags
from dns.rdatatype import *
from dns.rdataclass import *
from dns.rcode import *
@ -42,6 +42,8 @@ def logquery(type, qname):
# 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 ugly. it works the same as for good., but returns garbage to non-empty terminals
############################################################################
def create_response(msg):
m = dns.message.from_wire(msg)
@ -56,6 +58,7 @@ def create_response(msg):
typename = "ADDR"
bad = False
slow = False
ugly = False
# log this query
with open("query.log", "a") as f:
@ -69,6 +72,10 @@ def create_response(msg):
bad = True
suffix = "bad."
lqname = lqname[:-4]
elif lqname.endswith("ugly."):
ugly = True
suffix = "ugly."
lqname = lqname[:-5]
elif lqname.endswith("good."):
suffix = "good."
lqname = lqname[:-5]
@ -83,14 +90,19 @@ def create_response(msg):
# 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"))
r.flags |= dns.flags.AA
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"))
r.flags |= dns.flags.AA
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))
r.flags |= dns.flags.AA
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)
if ugly:
r.set_rcode(FORMERR)
else:
r.set_rcode(REFUSED)

View file

@ -28,5 +28,5 @@ 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
ugly. NS ns2.ugly.
ns2.ugly. A 10.53.0.2

View file

@ -85,6 +85,29 @@ for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "query for .ugly 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.ugly. @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.ugly. 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
ADDR icky.icky.icky.ptang.zoop.boing.ugly.
ADDR ns3.ugly.
ADDR ns3.ugly.
ADDR a.bit.longer.ns.name.ugly.
ADDR a.bit.longer.ns.name.ugly.
__EOF
echo "ADDR icky.icky.icky.ptang.zoop.boing.ugly." | diff ans3/query.log - > /dev/null || ret=1
echo "ADDR icky.icky.icky.ptang.zoop.boing.ugly." | 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
@ -94,31 +117,22 @@ $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 good.
NS boing.good.
NS zoop.boing.good.
ADDR ns3.good.
ADDR 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.
ADDR a.bit.longer.ns.name.good.
ADDR a.bit.longer.ns.name.good.
__EOF
cat << __EOF | diff ans3/query.log - > /dev/null || ret=1
NS zoop.boing.good.
NS ptang.zoop.boing.good.
NS icky.ptang.zoop.boing.good.
__EOF
cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.ptang.zoop.boing.good.
NS icky.icky.ptang.zoop.boing.good.
ADDR icky.icky.icky.ptang.zoop.boing.good.
__EOF
@ -134,7 +148,10 @@ $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
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS bad.
NS boing.bad.
__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`
@ -149,12 +166,11 @@ 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 bad.
NS boing.bad.
ADDR icky.icky.icky.ptang.zoop.boing.bad.
ADDR ns3.bad.
ADDR ns3.bad.
NS name.bad.
NS name.bad.
ADDR a.bit.longer.ns.name.bad.
ADDR a.bit.longer.ns.name.bad.
__EOF
@ -164,6 +180,52 @@ for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "query for .ugly 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.ugly. @10.53.0.6 > dig.out.test$n
grep "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1
sleep 1
cat << __EOF | diff ans2/query.log - > /dev/null || ret=1
NS ugly.
NS boing.ugly.
NS boing.ugly.
NS boing.ugly.
__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`
$RNDCCMD 10.53.0.6 flush
n=`expr $n + 1`
echo_i "query for .ugly 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.ugly. @10.53.0.7 > dig.out.test$n
grep "status: NOERROR" dig.out.test$n > /dev/null || (ret=1; echo "A")
grep "icky.icky.icky.ptang.zoop.boing.ugly. 1 IN A 192.0.2.1" dig.out.test$n > /dev/null || (ret=1; echo "X")
sleep 1
cat << __EOF | diff ans2/query.log - > /dev/null || (ret=1; echo "Y")
NS ugly.
NS boing.ugly.
NS boing.ugly.
NS boing.ugly.
ADDR icky.icky.icky.ptang.zoop.boing.ugly.
ADDR ns3.ugly.
ADDR ns3.ugly.
ADDR a.bit.longer.ns.name.ugly.
ADDR a.bit.longer.ns.name.ugly.
__EOF
echo "ADDR icky.icky.icky.ptang.zoop.boing.ugly." | diff ans3/query.log - > /dev/null || ret=1
echo "ADDR icky.icky.icky.ptang.zoop.boing.ugly." | 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`
$RNDCCMD 10.53.0.7 flush
n=`expr $n + 1`
echo_i "query for .slow is properly minimized when qname-minimization is on ($n)"
ret=0
@ -174,24 +236,22 @@ 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 slow.
NS boing.slow.
NS zoop.boing.slow.
ADDR ns3.slow.
ADDR 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.
NS icky.ptang.zoop.boing.slow.
ADDR a.bit.longer.ns.name.slow.
ADDR a.bit.longer.ns.name.slow.
__EOF
cat << __EOF | diff ans3/query.log - > /dev/null || ret=1
NS zoop.boing.slow.
NS ptang.zoop.boing.slow.
NS icky.ptang.zoop.boing.slow.
__EOF
cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.ptang.zoop.boing.slow.
NS icky.icky.ptang.zoop.boing.slow.
ADDR icky.icky.icky.ptang.zoop.boing.slow.
__EOF
@ -220,25 +280,6 @@ for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null
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.
ADDR 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
@ -249,25 +290,22 @@ 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 good.
NS boing.good.
NS zoop.boing.good.
ADDR ns3.good.
ADDR 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.
ADDR a.bit.longer.ns.name.good.
ADDR a.bit.longer.ns.name.good.
__EOF
cat << __EOF | diff ans3/query.log - > /dev/null || ret=1
NS zoop.boing.good.
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.
# There's no NS icky.icky.icky.ptang.zoop.boing.good. query - we skipped it.
cat << __EOF | diff ans4/query.log - > /dev/null || ret=1
NS icky.ptang.zoop.boing.good.
NS icky.icky.ptang.zoop.boing.good.
ADDR more.icky.icky.icky.ptang.zoop.boing.good.
__EOF

View file

@ -21,7 +21,6 @@ options {
notify no;
minimal-responses no;
recursion yes;
qname-minimization disabled;
dnssec-validation yes;
};

View file

@ -27,7 +27,6 @@ options {
notify yes;
minimal-responses no;
recursion yes;
qname-minimization disabled;
dnssec-validation yes;
response-policy {

View file

@ -21,7 +21,6 @@ options {
notify no;
minimal-responses no;
recursion yes;
qname-minimization disabled;
dnssec-validation yes;
};

View file

@ -29,7 +29,6 @@ options {
notify yes;
minimal-responses no;
recursion yes;
qname-minimization disabled;
dnssec-validation yes;
# turn rpz on or off

View file

@ -23,7 +23,6 @@ options {
forwarders { 10.53.0.3; };
minimal-responses no;
recursion yes;
qname-minimization disabled;
dnssec-validation yes;
response-policy {

View file

@ -21,7 +21,6 @@ options {
listen-on-v6 { none; };
minimal-responses no;
recursion yes;
qname-minimization disabled;
dnssec-validation yes;
response-policy {

View file

@ -4024,7 +4024,7 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone,
adbname);
name = dns_fixedname_initname(&fixed);
result = dns_view_findzonecut(adb->view, &adbname->name, name,
0, 0, true, false,
NULL, 0, 0, true, false,
&rdataset, NULL);
if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
goto cleanup;
@ -4032,14 +4032,6 @@ fetch_name(dns_adbname_t *adbname, bool 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;
@ -4047,6 +4039,14 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone,
}
fetch->depth = depth;
/*
* We're not minimizing this query, as nothing user-related should
* be leaked here.
* However, if we'd ever want to change it we'd have to modify
* createfetch to find deepest cached name when we're providing
* domain and nameservers.
*/
result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
type, name, nameservers, NULL,
NULL, 0, options, depth, qc,

View file

@ -559,10 +559,13 @@ isc_result_t
dns_db_findzonecut(dns_db_t *db, const dns_name_t *name,
unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
dns_name_t *dcname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
{
/*
* Find the deepest known zonecut which encloses 'name' in 'db'.
* foundname is the zonecut, dcname is the deepest name we have
* in database that is part of queried name.
*/
REQUIRE(DNS_DB_VALID(db));
@ -574,7 +577,8 @@ dns_db_findzonecut(dns_db_t *db, const dns_name_t *name,
! dns_rdataset_isassociated(sigrdataset)));
return ((db->methods->findzonecut)(db, name, options, now, nodep,
foundname, rdataset, sigrdataset));
foundname, dcname,
rdataset, sigrdataset));
}
void

View file

@ -311,7 +311,8 @@ static isc_result_t
findzonecut(dns_db_t *db, const dns_name_t *name,
unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
dns_name_t *dcname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
{
dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
@ -322,6 +323,7 @@ findzonecut(dns_db_t *db, const dns_name_t *name,
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);

View file

@ -147,7 +147,7 @@ static struct tt {
int type;
char classname[TYPECLASSBUF];
char typename[TYPECLASSBUF];
char dirname[DIRNAMESIZE]; /* XXX Should be max path length */
char dirname[DIRNAMESIZE-30]; /* XXX Should be max path length */
} *types;
static struct ttnam {

View file

@ -103,6 +103,7 @@ typedef struct dns_dbmethods {
unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep,
dns_name_t *foundname,
dns_name_t *dcname,
dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset);
void (*attachnode)(dns_db_t *db,
@ -936,7 +937,8 @@ isc_result_t
dns_db_findzonecut(dns_db_t *db, const dns_name_t *name,
unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
dns_name_t *dcname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset);
/*%<
* Find the deepest known zonecut which encloses 'name' in 'db'.
*
@ -955,6 +957,8 @@ dns_db_findzonecut(dns_db_t *db, const dns_name_t *name,
*
* \li 'foundname' is a valid name with a dedicated buffer.
*
* \li 'dcname' is a valid name with a dedicated buffer.
*
* \li 'rdataset' is NULL, or is a valid unassociated rdataset.
*
* Ensures, on a non-error completion:
@ -964,6 +968,9 @@ dns_db_findzonecut(dns_db_t *db, const dns_name_t *name,
* \li If foundname != NULL, then it contains the full name of the
* found node.
*
* \li If dcname != NULL, then it contains the deepest cached name
* that exists in the database.
*
* \li If rdataset != NULL and type != dns_rdatatype_any, then
* rdataset is bound to the found rdataset.
*

View file

@ -704,7 +704,7 @@ dns_view_simplefind(dns_view_t *view, const dns_name_t *name,
isc_result_t
dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
dns_name_t *fname, isc_stdtime_t now,
dns_name_t *fname, dns_name_t *dcname, isc_stdtime_t now,
unsigned int options,
bool use_hints, bool use_cache,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
@ -730,6 +730,8 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
*\li If the DNS_DBFIND_NOEXACT option is set, then the zonecut returned
* (if any) will be the deepest known ancestor of 'name'.
*
*\li If dcname is not NULL the deepest cached name is copied to it.
*
* Requires:
*
*\li 'view' is a valid, frozen view.

View file

@ -4307,7 +4307,7 @@ zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
static isc_result_t
zone_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
isc_stdtime_t now, dns_dbnode_t **nodep,
dns_name_t *foundname,
dns_name_t *foundname, dns_name_t *dcname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
UNUSED(db);
@ -4316,6 +4316,7 @@ zone_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);
@ -5034,7 +5035,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
static isc_result_t
cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
isc_stdtime_t now, dns_dbnode_t **nodep,
dns_name_t *foundname,
dns_name_t *foundname, dns_name_t *dcname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
dns_rbtnode_t *node = NULL;
@ -5045,6 +5046,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
rdatasetheader_t *found, *foundsig;
unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
isc_rwlocktype_t locktype;
bool dcnull = (dcname == NULL);
search.rbtdb = (dns_rbtdb_t *)db;
@ -5064,6 +5066,10 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
search.now = now;
if (dcnull) {
dcname = foundname;
}
if ((options & DNS_DBFIND_NOEXACT) != 0)
rbtoptions |= DNS_RBTFIND_NOEXACT;
@ -5072,17 +5078,18 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
/*
* Search down from the root of the tree.
*/
result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
result = dns_rbt_findnode(search.rbtdb->tree, name, dcname, &node,
&search.chain, rbtoptions, NULL, &search);
if (result == DNS_R_PARTIALMATCH) {
find_ns:
result = find_deepest_zonecut(&search, node, nodep, foundname,
rdataset, sigrdataset);
goto tree_exit;
} else if (result != ISC_R_SUCCESS)
} else if (result != ISC_R_SUCCESS) {
goto tree_exit;
} else if (!dcnull) {
dns_name_copy(dcname, foundname, NULL);
}
/*
* We now go looking for an NS rdataset at the node.
*/
@ -5129,7 +5136,9 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
* No NS records here.
*/
NODE_UNLOCK(lock, locktype);
goto find_ns;
result = find_deepest_zonecut(&search, node, nodep, foundname,
rdataset, sigrdataset);
goto tree_exit;
}
if (nodep != NULL) {

View file

@ -261,8 +261,8 @@ struct fetchctx {
/*% Not locked. */
unsigned int magic;
dns_resolver_t * res;
dns_name_t fullname;
dns_rdatatype_t fulltype;
dns_name_t name;
dns_rdatatype_t type;
unsigned int options;
unsigned int bucketnum;
unsigned int dbucketnum;
@ -311,10 +311,12 @@ struct fetchctx {
isc_counter_t * qc;
bool minimized;
unsigned int qmin_labels;
unsigned int qmin_steps;
bool ip6arpaskip;
dns_name_t name;
dns_rdatatype_t type;
bool ip6arpaskip;
dns_name_t qminname;
dns_rdatatype_t qmintype;
dns_fetch_t * qminfetch;
dns_rdataset_t qminrrset;
dns_name_t qmindcname;
/*%
* The number of events we're waiting for.
@ -558,6 +560,12 @@ struct dns_resolver {
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
#define NXDOMAIN_RESULT(r) ((r) == DNS_R_NXDOMAIN || \
(r) == DNS_R_NCACHENXDOMAIN)
#define NXRRSET_RESULT(r) ((r) == DNS_R_NCACHENXRRSET || \
(r) == DNS_R_NXRRSET || \
(r) == DNS_R_HINTNXRRSET)
#ifdef ENABLE_AFL
bool dns_fuzzing_resolver = false;
void dns_resolver_setfuzzing() {
@ -597,6 +605,7 @@ static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name,
dns_name_t **noqname);
static void fctx_increference(fetchctx_t *fctx);
static bool fctx_decreference(fetchctx_t *fctx);
static void resume_qmin(isc_task_t *task, isc_event_t *event);
/*%
* The structure and functions defined below implement the resolver
@ -766,12 +775,6 @@ 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);
@ -3339,6 +3342,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
options, now, NULL,
res->view->dstport,
fctx->depth + 1, fctx->qc, &find);
if (result != ISC_R_SUCCESS) {
if (result == DNS_R_ALIAS) {
char namebuf[DNS_NAME_FORMATSIZE];
@ -3930,6 +3934,7 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
isc_result_t result;
dns_adbaddrinfo_t *addrinfo = NULL;
dns_resolver_t *res;
isc_task_t *task;
unsigned int bucketnum;
bool bucket_empty;
@ -3938,6 +3943,7 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
REQUIRE(!ADDRWAIT(fctx));
res = fctx->res;
bucketnum = fctx->bucketnum;
/* We've already exceeded maximum query count */
if (isc_counter_used(fctx->qc) > res->maxqueries) {
@ -3951,6 +3957,26 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
return;
}
/*
* We're minimizing and we're not yet at the final NS -
* we need to launch a query for NS for 'upper' domain
*/
if (fctx->minimized == true) {
unsigned int options = fctx->options;
options &= ~DNS_FETCHOPT_QMINIMIZE;
fctx_increference(fctx);
task = res->buckets[bucketnum].task;
result = dns_resolver_createfetch(fctx->res, &fctx->qminname,
fctx->qmintype, NULL,
NULL, NULL, NULL, 0,
options, 0, fctx->qc,
task, resume_qmin, fctx,
&fctx->qminrrset, NULL,
&fctx->qminfetch);
return;
}
addrinfo = fctx_nextaddress(fctx);
/* Try to find an address that isn't over quota */
@ -4005,7 +4031,6 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
}
}
bucketnum = fctx->bucketnum;
fctx_increference(fctx);
result = fctx_query(fctx, addrinfo, fctx->options);
if (result != ISC_R_SUCCESS) {
@ -4019,6 +4044,118 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
inc_stats(res, dns_resstatscounter_retry);
}
static void
resume_qmin(isc_task_t *task, isc_event_t *event) {
dns_fetchevent_t *fevent;
dns_resolver_t *res;
fetchctx_t *fctx;
isc_result_t result;
bool bucket_empty;
bool locked = false;
unsigned int bucketnum;
unsigned int findoptions = 0;
dns_name_t *fname, *dcname;
dns_fixedname_t ffixed, dcfixed;
fname = dns_fixedname_initname(&ffixed);
dcname = dns_fixedname_initname(&dcfixed);
REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
fevent = (dns_fetchevent_t *)event;
fctx = event->ev_arg;
REQUIRE(VALID_FCTX(fctx));
res = fctx->res;
UNUSED(task);
FCTXTRACE("resume_qmin");
if (fevent->node != NULL)
dns_db_detachnode(fevent->db, &fevent->node);
if (fevent->db != NULL)
dns_db_detach(&fevent->db);
bucketnum = fctx->bucketnum;
if (dns_rdataset_isassociated(fevent->rdataset)) {
dns_rdataset_disassociate(fevent->rdataset);
}
result = fevent->result;
fevent = NULL;
isc_event_free(&event);
dns_resolver_destroyfetch(&fctx->qminfetch);
/*
* Note: fevent->rdataset must be disassociated and
* isc_event_free(&event) be called before resuming
* processing of the 'fctx' to prevent use-after-free.
* 'fevent' is set to NULL so as to not have a dangling
* pointer.
*/
if (result == ISC_R_CANCELED) {
fctx_done(fctx, result, __LINE__);
goto cleanup;
} else if (NXDOMAIN_RESULT(result) || result == DNS_R_FORMERR ||
result == DNS_R_REMOTEFORMERR)
{
if ((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 nxdomain", fctx->info);
fctx->qmin_labels = DNS_MAX_LABELS + 1;
} else {
fctx_done(fctx, result, __LINE__);
goto cleanup;
}
}
if (dns_rdataset_isassociated(&fctx->nameservers)) {
dns_rdataset_disassociate(&fctx->nameservers);
}
if (dns_rdatatype_atparent(fctx->type)) {
findoptions |= DNS_DBFIND_NOEXACT;
}
result = dns_view_findzonecut(res->view, &fctx->name, fname,
dcname, fctx->now, findoptions,
true, true, &fctx->nameservers, NULL);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
return;
}
fcount_decr(fctx);
dns_name_free(&fctx->domain, fctx->mctx);
dns_name_init(&fctx->domain, NULL);
result = dns_name_dup(fname, fctx->mctx, &fctx->domain);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
return;
}
dns_name_free(&fctx->qmindcname, fctx->mctx);
dns_name_init(&fctx->qmindcname, NULL);
result = dns_name_dup(dcname, fctx->mctx, &fctx->qmindcname);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
return;
}
fctx->ns_ttl = fctx->nameservers.ttl;
fctx->ns_ttl_ok = true;
fctx_minimize_qname(fctx);
fctx_try(fctx, true, false);
cleanup:
INSIST(event == NULL);
INSIST(fevent == NULL);
if (!locked)
LOCK(&res->buckets[bucketnum].lock);
bucket_empty = fctx_decreference(fctx);
UNLOCK(&res->buckets[bucketnum].lock);
if (bucket_empty)
empty_bucket(res);
}
static bool
fctx_unlink(fetchctx_t *fctx) {
dns_resolver_t *res;
@ -4119,8 +4256,9 @@ 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_name_free(&fctx->qminname, fctx->mctx);
dns_name_free(&fctx->qmindcname, fctx->mctx);
dns_db_detach(&fctx->cache);
dns_adb_detach(&fctx->adb);
isc_mem_free(fctx->mctx, fctx->info);
@ -4402,7 +4540,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->fulltype;
event->qtype = fctx->type;
event->db = NULL;
event->node = NULL;
event->rdataset = rdataset;
@ -4453,7 +4591,6 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
isc_result_t result;
isc_result_t iresult;
isc_interval_t interval;
dns_fixedname_t fixed;
unsigned int findoptions = 0;
char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
char typebuf[DNS_RDATATYPE_FORMATSIZE];
@ -4498,15 +4635,15 @@ 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);
dns_name_init(&fctx->qminname, NULL);
result = dns_name_dup(name, mctx, &fctx->qminname);
if (result != ISC_R_SUCCESS)
goto cleanup_name;
goto cleanup_qminname;
dns_name_init(&fctx->domain, NULL);
dns_rdataset_init(&fctx->nameservers);
fctx->fulltype = type;
fctx->type = type;
fctx->qmintype = type;
fctx->options = options;
/*
* Note! We do not attach to the task. We are relying on the
@ -4524,7 +4661,9 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
fctx->minimized = false;
fctx->ip6arpaskip = false;
fctx->qmin_labels = 1;
fctx->qmin_steps = 0;
fctx->qminfetch = NULL;
dns_rdataset_init(&fctx->qminrrset);
dns_name_init(&fctx->qmindcname, NULL);
isc_stdtime_get(&fctx->now);
ISC_LIST_INIT(fctx->queries);
ISC_LIST_INIT(fctx->finds);
@ -4576,6 +4715,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
if (domain == NULL) {
dns_forwarders_t *forwarders = NULL;
dns_fixedname_t fixed;
unsigned int labels;
const dns_name_t *fwdname = name;
dns_name_t suffix;
@ -4602,6 +4742,9 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
fctx->fwdpolicy = forwarders->fwdpolicy;
if (fctx->fwdpolicy != dns_fwdpolicy_only) {
dns_fixedname_t dcfixed;
dns_name_t *dcname;
dcname = dns_fixedname_initname(&dcfixed);
/*
* The caller didn't supply a query domain and
* nameservers, and we're not in forward-only mode,
@ -4610,17 +4753,22 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
if (dns_rdatatype_atparent(fctx->type))
findoptions |= DNS_DBFIND_NOEXACT;
result = dns_view_findzonecut(res->view, name, fname,
0, findoptions, true,
true,
dcname, fctx->now,
findoptions, true, true,
&fctx->nameservers,
NULL);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
goto cleanup_nameservers;
}
result = dns_name_dup(fname, mctx, &fctx->domain);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
goto cleanup_nameservers;
}
result = dns_name_dup(dcname, mctx, &fctx->qmindcname);
if (result != ISC_R_SUCCESS) {
goto cleanup_domain;
}
fctx->ns_ttl = fctx->nameservers.ttl;
fctx->ns_ttl_ok = true;
} else {
@ -4628,13 +4776,27 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
* We're in forward-only mode. Set the query domain.
*/
result = dns_name_dup(fname, mctx, &fctx->domain);
if (result != ISC_R_SUCCESS)
goto cleanup_fullname;
if (result != ISC_R_SUCCESS) {
goto cleanup_name;
}
result = dns_name_dup(fname, mctx, &fctx->qmindcname);
if (result != ISC_R_SUCCESS) {
goto cleanup_domain;
}
/*
* Disable query minimization
*/
options &= ~DNS_FETCHOPT_QMINIMIZE;
}
} else {
result = dns_name_dup(domain, mctx, &fctx->domain);
if (result != ISC_R_SUCCESS)
goto cleanup_fullname;
if (result != ISC_R_SUCCESS) {
goto cleanup_name;
}
result = dns_name_dup(domain, mctx, &fctx->qmindcname);
if (result != ISC_R_SUCCESS) {
goto cleanup_domain;
}
dns_rdataset_clone(nameservers, &fctx->nameservers);
fctx->ns_ttl = fctx->nameservers.ttl;
fctx->ns_ttl_ok = true;
@ -4754,17 +4916,19 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
cleanup_domain:
if (dns_name_countlabels(&fctx->domain) > 0)
dns_name_free(&fctx->domain, mctx);
if (dns_name_countlabels(&fctx->qmindcname) > 0)
dns_name_free(&fctx->qmindcname, mctx);
cleanup_nameservers:
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);
cleanup_qminname:
dns_name_free(&fctx->qminname, mctx);
cleanup_info:
isc_mem_free(mctx, fctx->info);
@ -6469,10 +6633,13 @@ 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 bool
is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
@ -7768,12 +7935,7 @@ rctx_answer(respctx_t *rctx) {
fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
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 ||
if ((fctx->rmessage->flags & DNS_MESSAGEFLAG_AA) != 0 ||
ISFORWARDER(query->addrinfo))
{
result = rctx_answer_positive(rctx);
@ -8478,19 +8640,6 @@ 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);
}
@ -8512,21 +8661,6 @@ 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.
@ -8894,10 +9028,6 @@ 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;
/*
@ -8943,39 +9073,6 @@ 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
@ -8992,6 +9089,8 @@ rctx_follow_referral(respctx_t *rctx) {
rctx->fctx->neterr = 0;
rctx->fctx->badresp = 0;
rctx->fctx->adberr = 0;
return (ISC_R_COMPLETE);
}
/*
@ -9058,11 +9157,12 @@ rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
}
if (rctx->get_nameservers) {
dns_fixedname_t foundname;
dns_name_t *name, *fname;
dns_fixedname_t foundname, founddc;
dns_name_t *name, *fname, *dcname;
unsigned int findoptions = 0;
fname = dns_fixedname_initname(&foundname);
dcname = dns_fixedname_initname(&founddc);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
@ -9075,11 +9175,9 @@ rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
} else {
name = &fctx->domain;
}
result = dns_view_findzonecut(fctx->res->view,
name, fname,
fctx->now, findoptions,
true, true,
&fctx->nameservers,
result = dns_view_findzonecut(fctx->res->view, name, fname,
dcname, fctx->now, findoptions,
true, true, &fctx->nameservers,
NULL);
if (result != ISC_R_SUCCESS) {
FCTXTRACE("couldn't find a zonecut");
@ -9096,6 +9194,7 @@ rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
}
fcount_decr(fctx);
dns_name_free(&fctx->domain, fctx->mctx);
dns_name_init(&fctx->domain, NULL);
result = dns_name_dup(fname, fctx->mctx, &fctx->domain);
@ -9103,6 +9202,14 @@ rctx_nextserver(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo,
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
dns_name_free(&fctx->qmindcname, fctx->mctx);
dns_name_init(&fctx->qmindcname, NULL);
result = dns_name_dup(dcname, fctx->mctx, &fctx->qmindcname);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
result = fcount_incr(fctx, true);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
@ -9367,20 +9474,8 @@ rctx_badserver(respctx_t *rctx, isc_result_t result) {
return (ISC_R_SUCCESS);
}
/*
* If we're minimizing in relaxed mode try to disable minimization.
*/
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 ((fctx->rmessage->rcode == dns_rcode_formerr) &&
(rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0)
if ((fctx->rmessage->rcode == dns_rcode_formerr) &&
(rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0)
{
/*
* It's very likely they don't like EDNS0.
@ -10189,9 +10284,9 @@ fctx_match(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type,
ISC_LIST_EMPTY(fctx->events))
return (false);
if (fctx->fulltype != type || fctx->options != options)
if (fctx->type != type || fctx->options != options)
return (false);
return (dns_name_equal(&fctx->fullname, name));
return (dns_name_equal(&fctx->name, name));
}
static inline void
@ -10217,16 +10312,17 @@ log_fetch(const dns_name_t *name, dns_rdatatype_t type) {
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);
dlabels = dns_name_countlabels(&fctx->qmindcname);
nlabels = dns_name_countlabels(&fctx->name);
dns_name_free(&fctx->qminname, fctx->mctx);
dns_name_init(&fctx->qminname, NULL);
if (dlabels > fctx->qmin_labels) {
fctx->qmin_labels = dlabels+1;
} else {
fctx->qmin_labels++;
}
if (fctx->ip6arpaskip) {
/*
* For ip6.arpa we want to skip some of the labels, with
@ -10235,43 +10331,39 @@ fctx_minimize_qname(fetchctx_t *fctx) {
* 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 (fctx->qmin_labels < 7) {
fctx->qmin_labels = 7;
} else if (fctx->qmin_labels < 11) {
fctx->qmin_labels = 11;
} else if (fctx->qmin_labels < 15) {
fctx->qmin_labels = 15;
} else if (fctx->qmin_labels < 17) {
fctx->qmin_labels = 17;
} else if (fctx->qmin_labels < 19) {
fctx->qmin_labels = 19;
} else if (fctx->qmin_labels > 19) {
fctx->qmin_labels = 35;
}
} 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;
} else if (fctx->qmin_labels > DNS_QMIN_MAXLABELS) {
fctx->qmin_labels = DNS_MAX_LABELS + 1;
}
if (dlabels + fctx->qmin_labels < nlabels) {
if (fctx->qmin_labels < nlabels) {
/*
* We want to query for
* [qmin_labels from fctx->fullname] + fctx->domain
* We want to query for qmin_labels from fctx->name
*/
dns_fixedname_t fname;
dns_fixedname_init(&fname);
dns_name_split(&fctx->fullname,
dlabels + fctx->qmin_labels,
dns_name_split(&fctx->name,
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->qminname);
fctx->qmintype = dns_rdatatype_ns;
fctx->minimized = 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->qmintype = fctx->type;
dns_name_dup(&fctx->name, fctx->mctx, &fctx->qminname);
fctx->minimized = false;
}
}
@ -10540,8 +10632,7 @@ dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx,
"%06" PRIu64 ": %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,"
"qminsteps:%u]",
"badresp:%u,adberr:%u,findfail:%u,valfail:%u]",
__FILE__, fctx->exitline, fctx->info,
fctx->duration / US_PER_SEC,
fctx->duration % US_PER_SEC,
@ -10551,8 +10642,7 @@ 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->qmin_steps);
fctx->findfail, fctx->valfail);
fctx->logged = true;
}

View file

@ -986,7 +986,8 @@ findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
static isc_result_t
findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
dns_name_t *dcname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
{
UNUSED(db);
UNUSED(name);
@ -994,6 +995,7 @@ findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);

View file

@ -715,7 +715,8 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create,
static isc_result_t
findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
dns_name_t *dcname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
{
UNUSED(db);
UNUSED(name);
@ -723,6 +724,7 @@ findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);

View file

@ -3400,7 +3400,7 @@ proveunsecure(dns_validator_t *val, bool have_ds, bool resume)
*/
if (result == DNS_R_NXRRSET &&
!dns_rdataset_isassociated(&val->frdataset) &&
dns_view_findzonecut(val->view, tname, found,
dns_view_findzonecut(val->view, tname, found, NULL,
0, 0, false, false,
NULL, NULL) == ISC_R_SUCCESS &&
dns_name_equal(tname, found)) {

View file

@ -1254,7 +1254,7 @@ dns_view_simplefind(dns_view_t *view, const dns_name_t *name,
isc_result_t
dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
dns_name_t *fname, isc_stdtime_t now,
dns_name_t *fname, dns_name_t *dcname, isc_stdtime_t now,
unsigned int options, bool use_hints,
bool use_cache, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset)
@ -1357,7 +1357,8 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
}
} else {
result = dns_db_findzonecut(db, name, options, now, NULL,
fname, rdataset, sigrdataset);
fname, dcname, rdataset,
sigrdataset);
if (result == ISC_R_SUCCESS) {
if (zfname != NULL &&
(!dns_name_issubdomain(fname, zfname) ||
@ -1401,6 +1402,11 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
result = dns_name_copy(zfname, fname, NULL);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (dcname != NULL) {
result = dns_name_copy(zfname, dcname, NULL);
if (result != ISC_R_SUCCESS)
goto cleanup;
}
dns_rdataset_clone(&zrdataset, rdataset);
if (sigrdataset != NULL &&
dns_rdataset_isassociated(&zrdataset))
@ -1420,6 +1426,8 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
if (dns_rdataset_isassociated(rdataset))
dns_rdataset_disassociate(rdataset);
result = ISC_R_NOTFOUND;
} else if (dcname != NULL) {
dns_name_copy(fname, dcname, NULL);
}
}

View file

@ -10113,7 +10113,7 @@ query_addbestns(query_ctx_t *qctx) {
} else {
result = dns_db_findzonecut(db, client->query.qname,
client->query.dboptions,
client->now, &node, fname,
client->now, &node, fname, NULL,
rdataset, sigrdataset);
if (result == ISC_R_SUCCESS) {
if (zfname != NULL &&