this makes the cache more efficient and eliminates duplicates queries.
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,
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));
}
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 *
#
# 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
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
+ ugly = False
slow = False
# log this query
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"))
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"))
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]
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 \
"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
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 *
# 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)
if typename == "A" or typename == "AAAA":
typename = "ADDR"
bad = False
+ ugly = False
slow = False
# log this query
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]
# 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)
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 *
# 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)
typename = "ADDR"
bad = False
slow = False
+ ugly = False
# log this query
with open("query.log", "a") as f:
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]
# 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)
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
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
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
$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`
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
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
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
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
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
notify no;
minimal-responses no;
recursion yes;
- qname-minimization disabled;
dnssec-validation yes;
};
notify yes;
minimal-responses no;
recursion yes;
- qname-minimization disabled;
dnssec-validation yes;
response-policy {
notify no;
minimal-responses no;
recursion yes;
- qname-minimization disabled;
dnssec-validation yes;
};
notify yes;
minimal-responses no;
recursion yes;
- qname-minimization disabled;
dnssec-validation yes;
# turn rpz on or off
forwarders { 10.53.0.3; };
minimal-responses no;
recursion yes;
- qname-minimization disabled;
dnssec-validation yes;
response-policy {
listen-on-v6 { none; };
minimal-responses no;
recursion yes;
- qname-minimization disabled;
dnssec-validation yes;
response-policy {
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;
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;
}
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,
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));
! dns_rdataset_isassociated(sigrdataset)));
return ((db->methods->findzonecut)(db, name, options, now, nodep,
- foundname, rdataset, sigrdataset));
+ foundname, dcname,
+ rdataset, sigrdataset));
}
void
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;
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
+ UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);
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 {
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,
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'.
*
*
* \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:
* \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.
*
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);
*\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.
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);
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
+ UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);
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;
rdatasetheader_t *found, *foundsig;
unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
isc_rwlocktype_t locktype;
+ bool dcnull = (dcname == NULL);
search.rbtdb = (dns_rbtdb_t *)db;
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;
/*
* 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.
*/
* 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) {
/*% 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;
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.
#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() {
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
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);
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];
isc_result_t result;
dns_adbaddrinfo_t *addrinfo = NULL;
dns_resolver_t *res;
+ isc_task_t *task;
unsigned int bucketnum;
bool bucket_empty;
REQUIRE(!ADDRWAIT(fctx));
res = fctx->res;
+ bucketnum = fctx->bucketnum;
/* We've already exceeded maximum query count */
if (isc_counter_used(fctx->qc) > res->maxqueries) {
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 */
}
}
- bucketnum = fctx->bucketnum;
fctx_increference(fctx);
result = fctx_query(fctx, addrinfo, fctx->options);
if (result != ISC_R_SUCCESS) {
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;
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);
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;
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];
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
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);
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;
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,
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 {
* 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;
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);
#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,
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);
} 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);
}
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.
check_answer, fctx);
}
#endif
- if (fctx->minimized) {
- (void)dns_rdataset_additionaldata(rctx->ns_rdataset,
- check_answer, fctx);
- }
fctx->attributes &= ~FCTX_ATTR_GLUING;
/*
log_ns_ttl(fctx, "DELEGATION");
rctx->result = DNS_R_DELEGATION;
- rctx_follow_referral(rctx);
- if (rctx->fctx->minimized) {
- /*
- * Reset the value
- */
- fctx->qmin_labels = 1;
- fctx_minimize_qname(rctx->fctx);
- }
- return (ISC_R_COMPLETE);
-}
-
-/*
- * rctx_answer_minimized():
- * Handles a positive response to a qname-minimized query.
- */
-static isc_result_t
-rctx_answer_minimized(respctx_t *rctx) {
- fetchctx_t *fctx = rctx->fctx;
-
- FCTXTRACE("rctx_answer_minimized");
- if (dns_rdataset_isassociated(&fctx->nameservers)) {
- dns_rdataset_disassociate(&fctx->nameservers);
- }
- rctx->result = DNS_R_DELEGATION;
- rctx_follow_referral(rctx);
- fctx->qmin_labels++;
- fctx_minimize_qname(rctx->fctx);
-
- return (ISC_R_SUCCESS);
-}
-
-static void
-rctx_follow_referral(respctx_t *rctx) {
/*
* Reinitialize 'rctx' to prepare for following the delegation:
* set the get_nameservers and next_server flags appropriately and
rctx->fctx->neterr = 0;
rctx->fctx->badresp = 0;
rctx->fctx->adberr = 0;
+
+ return (ISC_R_COMPLETE);
}
/*
}
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__);
} 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");
}
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);
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__);
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.
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
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
* 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;
}
}
"%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,
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;
}
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);
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
+ UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);
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);
UNUSED(now);
UNUSED(nodep);
UNUSED(foundname);
+ UNUSED(dcname);
UNUSED(rdataset);
UNUSED(sigrdataset);
*/
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)) {
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)
}
} 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) ||
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))
if (dns_rdataset_isassociated(rdataset))
dns_rdataset_disassociate(rdataset);
result = ISC_R_NOTFOUND;
+ } else if (dcname != NULL) {
+ dns_name_copy(fname, dcname, NULL);
}
}
} 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 &&