From: Witold Kręcicki Date: Wed, 13 Jun 2018 07:29:40 +0000 (+0200) Subject: QNAME miminimization should create a separate fetch context for each fetch - X-Git-Tag: v9.13.4~105^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70a1ba20ec19325bfc3df46fbcbf97481793cc68;p=thirdparty%2Fbind9.git QNAME miminimization should create a separate fetch context for each fetch - this makes the cache more efficient and eliminates duplicates queries. --- diff --git a/bin/tests/optional/db_test.c b/bin/tests/optional/db_test.c index 92ec7472bec..29d341a9c28 100644 --- a/bin/tests/optional/db_test.c +++ b/bin/tests/optional/db_test.c @@ -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, diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c index fd0f998b74a..a793a69f04e 100644 --- a/bin/tests/system/dyndb/driver/db.c +++ b/bin/tests/system/dyndb/driver/db.c @@ -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)); } diff --git a/bin/tests/system/qmin/ans2/ans.py b/bin/tests/system/qmin/ans2/ans.py index bb6a696737c..17a2ba4874e 100755 --- a/bin/tests/system/qmin/ans2/ans.py +++ b/bin/tests/system/qmin/ans2/ans.py @@ -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 diff --git a/bin/tests/system/qmin/ans3/ans.py b/bin/tests/system/qmin/ans3/ans.py index e3943328109..51d9ae2e7e6 100755 --- a/bin/tests/system/qmin/ans3/ans.py +++ b/bin/tests/system/qmin/ans3/ans.py @@ -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) diff --git a/bin/tests/system/qmin/ans4/ans.py b/bin/tests/system/qmin/ans4/ans.py index c48fc55a34b..1bbf017a9ef 100755 --- a/bin/tests/system/qmin/ans4/ans.py +++ b/bin/tests/system/qmin/ans4/ans.py @@ -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) diff --git a/bin/tests/system/qmin/ns1/root.db b/bin/tests/system/qmin/ns1/root.db index 83f157f8f04..294111df4df 100644 --- a/bin/tests/system/qmin/ns1/root.db +++ b/bin/tests/system/qmin/ns1/root.db @@ -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 diff --git a/bin/tests/system/qmin/tests.sh b/bin/tests/system/qmin/tests.sh index a485ec6f415..9c669d4358e 100755 --- a/bin/tests/system/qmin/tests.sh +++ b/bin/tests/system/qmin/tests.sh @@ -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 diff --git a/bin/tests/system/rpz/ns2/named.conf.in b/bin/tests/system/rpz/ns2/named.conf.in index 12a24630710..15226401e9b 100644 --- a/bin/tests/system/rpz/ns2/named.conf.in +++ b/bin/tests/system/rpz/ns2/named.conf.in @@ -21,7 +21,6 @@ options { notify no; minimal-responses no; recursion yes; - qname-minimization disabled; dnssec-validation yes; }; diff --git a/bin/tests/system/rpz/ns3/named.conf.in b/bin/tests/system/rpz/ns3/named.conf.in index 63b0aed6bbe..851a055bc9d 100644 --- a/bin/tests/system/rpz/ns3/named.conf.in +++ b/bin/tests/system/rpz/ns3/named.conf.in @@ -27,7 +27,6 @@ options { notify yes; minimal-responses no; recursion yes; - qname-minimization disabled; dnssec-validation yes; response-policy { diff --git a/bin/tests/system/rpz/ns4/named.conf.in b/bin/tests/system/rpz/ns4/named.conf.in index c875b10784e..04d6d188fd0 100644 --- a/bin/tests/system/rpz/ns4/named.conf.in +++ b/bin/tests/system/rpz/ns4/named.conf.in @@ -21,7 +21,6 @@ options { notify no; minimal-responses no; recursion yes; - qname-minimization disabled; dnssec-validation yes; }; diff --git a/bin/tests/system/rpz/ns5/named.conf.in b/bin/tests/system/rpz/ns5/named.conf.in index 76c9761cdc5..00d07252939 100644 --- a/bin/tests/system/rpz/ns5/named.conf.in +++ b/bin/tests/system/rpz/ns5/named.conf.in @@ -29,7 +29,6 @@ options { notify yes; minimal-responses no; recursion yes; - qname-minimization disabled; dnssec-validation yes; # turn rpz on or off diff --git a/bin/tests/system/rpz/ns6/named.conf.in b/bin/tests/system/rpz/ns6/named.conf.in index db0c43abc0c..1cf738399b5 100644 --- a/bin/tests/system/rpz/ns6/named.conf.in +++ b/bin/tests/system/rpz/ns6/named.conf.in @@ -23,7 +23,6 @@ options { forwarders { 10.53.0.3; }; minimal-responses no; recursion yes; - qname-minimization disabled; dnssec-validation yes; response-policy { diff --git a/bin/tests/system/rpz/ns7/named.conf.in b/bin/tests/system/rpz/ns7/named.conf.in index 192fe054f59..842f709923d 100644 --- a/bin/tests/system/rpz/ns7/named.conf.in +++ b/bin/tests/system/rpz/ns7/named.conf.in @@ -21,7 +21,6 @@ options { listen-on-v6 { none; }; minimal-responses no; recursion yes; - qname-minimization disabled; dnssec-validation yes; response-policy { diff --git a/lib/dns/adb.c b/lib/dns/adb.c index ae8c887340f..1572732bcd9 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -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, diff --git a/lib/dns/db.c b/lib/dns/db.c index cb3b2e6eec0..6f55aa3f0fe 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -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 diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c index 45a5d1b4651..465b96c3c9b 100644 --- a/lib/dns/ecdb.c +++ b/lib/dns/ecdb.c @@ -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); diff --git a/lib/dns/gen.c b/lib/dns/gen.c index 42535cdfb0f..1492aa67bd7 100644 --- a/lib/dns/gen.c +++ b/lib/dns/gen.c @@ -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 { diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index cb6c034342c..b7b28c4ed75 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -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. * diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index e7a70f27ba6..c8c7f25536c 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -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. diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 92d8d0ec727..b2da8abddf5 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -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) { diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index b4aa0946305..a19e5680ba8 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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; - } - } 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 (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 (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; } diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index 1a20f36b6f6..f70c17f4bc3 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -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); diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index 979cbf52d72..8bb66e8f1b5 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -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); diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 45d94bff815..9894059143f 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -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)) { diff --git a/lib/dns/view.c b/lib/dns/view.c index 53e04b67614..2ac81bdcca8 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -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); } } diff --git a/lib/ns/query.c b/lib/ns/query.c index a1fc0d3a947..fd423659f40 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -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 &&