mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge branch '2665-qname-minimization-disabled-after-first-resolution' into 'main'
QNAME minimization is bypassed with stale zonecut in cache Closes #2665 See merge request isc-projects/bind9!5327
This commit is contained in:
commit
b98594e048
8 changed files with 318 additions and 38 deletions
5
CHANGES
5
CHANGES
|
|
@ -1,3 +1,8 @@
|
|||
5694. [bug] BIND looks up the deepest zone cut in cache in order
|
||||
to iterate a query. When this node is stale, it may
|
||||
bypass QNAME minimization. This has been fixed.
|
||||
[GL #2665]
|
||||
|
||||
5693. [func] Restore support for reading 'timeout' and 'attempts'
|
||||
options from /etc/resolv.conf, and use their values
|
||||
in dig, host and nslookup. (Previously this was
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ def logquery(type, qname):
|
|||
with open("qlog", "a") as f:
|
||||
f.write("%s %s\n", type, qname)
|
||||
|
||||
def endswith(domain, labels):
|
||||
return domain.endswith("." + labels) or domain == labels
|
||||
|
||||
############################################################################
|
||||
# Respond to a DNS query.
|
||||
# For good. it serves:
|
||||
|
|
@ -51,6 +54,12 @@ def logquery(type, qname):
|
|||
# 8.2.6.0.1.0.0.2.ip6.arpa IN NS ns3.good
|
||||
# 1.0.0.2.ip6.arpa. IN NS ns2.good
|
||||
# ip6.arpa. IN NS ns2.good
|
||||
#
|
||||
# For stale. it serves:
|
||||
# a.b. NS ns.a.b.stale.
|
||||
# ns.a.b.stale. IN A 10.53.0.3
|
||||
# b. NS ns.b.stale.
|
||||
# ns.b.stale. IN A 10.53.0.4
|
||||
############################################################################
|
||||
def create_response(msg):
|
||||
m = dns.message.from_wire(msg)
|
||||
|
|
@ -75,9 +84,9 @@ def create_response(msg):
|
|||
r = dns.message.make_response(m)
|
||||
r.set_rcode(NOERROR)
|
||||
|
||||
if lqname.endswith("1.0.0.2.ip6.arpa."):
|
||||
if endswith(lqname, "1.0.0.2.ip6.arpa."):
|
||||
# Direct query - give direct answer
|
||||
if lqname.endswith("8.2.6.0.1.0.0.2.ip6.arpa."):
|
||||
if endswith(lqname, "8.2.6.0.1.0.0.2.ip6.arpa."):
|
||||
# Delegate to ns3
|
||||
r.authority.append(dns.rrset.from_text("8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, NS, "ns3.good."))
|
||||
r.additional.append(dns.rrset.from_text("ns3.good.", 60, IN, A, "10.53.0.3"))
|
||||
|
|
@ -89,7 +98,7 @@ def create_response(msg):
|
|||
# NS query at the apex
|
||||
r.answer.append(dns.rrset.from_text("1.0.0.2.ip6.arpa.", 30, 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):
|
||||
elif endswith("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.", lqname):
|
||||
# NODATA answer
|
||||
r.authority.append(dns.rrset.from_text("1.0.0.2.ip6.arpa.", 30, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
|
||||
else:
|
||||
|
|
@ -97,12 +106,12 @@ def create_response(msg):
|
|||
r.authority.append(dns.rrset.from_text("1.0.0.2.ip6.arpa.", 30, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
|
||||
r.set_rcode(NXDOMAIN)
|
||||
return r
|
||||
elif lqname.endswith("ip6.arpa."):
|
||||
elif endswith(lqname, "ip6.arpa."):
|
||||
if lqname == "ip6.arpa." and rrtype == NS:
|
||||
# NS query at the apex
|
||||
r.answer.append(dns.rrset.from_text("ip6.arpa.", 30, IN, NS, "ns2.good."))
|
||||
r.flags |= dns.flags.AA
|
||||
elif "1.0.0.2.ip6.arpa.".endswith(lqname):
|
||||
elif endswith("1.0.0.2.ip6.arpa.", lqname):
|
||||
# NODATA answer
|
||||
r.authority.append(dns.rrset.from_text("ip6.arpa.", 30, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
|
||||
else:
|
||||
|
|
@ -110,22 +119,47 @@ def create_response(msg):
|
|||
r.authority.append(dns.rrset.from_text("ip6.arpa.", 30, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1"))
|
||||
r.set_rcode(NXDOMAIN)
|
||||
return r
|
||||
elif lqname.endswith("bad."):
|
||||
elif endswith(lqname, "stale."):
|
||||
if endswith(lqname, "a.b.stale."):
|
||||
# Delegate to ns.a.b.stale.
|
||||
r.authority.append(dns.rrset.from_text("a.b.stale.", 2, IN, NS, "ns.a.b.stale."))
|
||||
r.additional.append(dns.rrset.from_text("ns.a.b.stale.", 2, IN, A, "10.53.0.3"))
|
||||
elif endswith(lqname, "b.stale."):
|
||||
# Delegate to ns.b.stale.
|
||||
r.authority.append(dns.rrset.from_text("b.stale.", 2, IN, NS, "ns.b.stale."))
|
||||
r.additional.append(dns.rrset.from_text("ns.b.stale.", 2, IN, A, "10.53.0.4"))
|
||||
elif lqname == "stale." and rrtype == NS:
|
||||
# NS query at the apex.
|
||||
r.answer.append(dns.rrset.from_text("stale.", 2, IN, NS, "ns2.stale."))
|
||||
r.flags |= dns.flags.AA
|
||||
elif lqname == "stale." and rrtype == SOA:
|
||||
# SOA query at the apex.
|
||||
r.answer.append(dns.rrset.from_text("stale.", 2, IN, SOA, "ns2.stale. hostmaster.stale. 1 2 3 4 5"))
|
||||
r.flags |= dns.flags.AA
|
||||
elif lqname == "stale.":
|
||||
# NODATA answer
|
||||
r.authority.append(dns.rrset.from_text("stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"))
|
||||
else:
|
||||
# NXDOMAIN
|
||||
r.authority.append(dns.rrset.from_text("stale.", 2, IN, SOA, "ns2.stale. hostmaster.arpa. 1 2 3 4 5"))
|
||||
r.set_rcode(NXDOMAIN)
|
||||
return r
|
||||
elif endswith(lqname, "bad."):
|
||||
bad = True
|
||||
suffix = "bad."
|
||||
lqname = lqname[:-4]
|
||||
elif lqname.endswith("ugly."):
|
||||
elif endswith(lqname, "ugly."):
|
||||
ugly = True
|
||||
suffix = "ugly."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("good."):
|
||||
elif endswith(lqname, "good."):
|
||||
suffix = "good."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("slow."):
|
||||
elif endswith(lqname, "slow."):
|
||||
slow = True
|
||||
suffix = "slow."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("fwd."):
|
||||
elif endswith(lqname, "fwd."):
|
||||
suffix = "fwd."
|
||||
lqname = lqname[:-4]
|
||||
else:
|
||||
|
|
@ -133,7 +167,7 @@ def create_response(msg):
|
|||
return r
|
||||
|
||||
# Good/bad/ugly differs only in how we treat non-empty terminals
|
||||
if lqname.endswith("zoop.boing."):
|
||||
if endswith(lqname, "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"))
|
||||
|
|
@ -168,9 +202,9 @@ def create_response(msg):
|
|||
else:
|
||||
r.authority.append(dns.rrset.from_text(suffix, 1, IN, SOA, "ns2." + suffix + " hostmaster.arpa. 2018050100 1 1 1 1"))
|
||||
if bad or not \
|
||||
("icky.icky.icky.ptang.zoop.boing.".endswith(lqname) or \
|
||||
"many.labels.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.".endswith(lqname) or \
|
||||
"a.bit.longer.ns.name.".endswith(lqname)):
|
||||
(endswith("icky.icky.icky.ptang.zoop.boing.", lqname) or \
|
||||
endswith("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.", lqname) or \
|
||||
endswith("a.bit.longer.ns.name.", lqname)):
|
||||
r.set_rcode(NXDOMAIN)
|
||||
if ugly:
|
||||
r.set_rcode(FORMERR)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ def logquery(type, qname):
|
|||
with open("qlog", "a") as f:
|
||||
f.write("%s %s\n", type, qname)
|
||||
|
||||
def endswith(domain, labels):
|
||||
return domain.endswith("." + labels) or domain == labels
|
||||
|
||||
############################################################################
|
||||
# Respond to a DNS query.
|
||||
# For good. it serves:
|
||||
|
|
@ -43,6 +46,9 @@ 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 stale. it serves:
|
||||
# a.b.stale. IN TXT peekaboo (resolver did not do qname minimization)
|
||||
############################################################################
|
||||
def create_response(msg):
|
||||
m = dns.message.from_wire(msg)
|
||||
|
|
@ -69,23 +75,46 @@ def create_response(msg):
|
|||
|
||||
ip6req = False
|
||||
|
||||
if lqname.endswith("bad."):
|
||||
if endswith(lqname, "bad."):
|
||||
bad = True
|
||||
suffix = "bad."
|
||||
lqname = lqname[:-4]
|
||||
elif lqname.endswith("ugly."):
|
||||
elif endswith(lqname, "ugly."):
|
||||
ugly = True
|
||||
suffix = "ugly."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("good."):
|
||||
elif endswith(lqname, "good."):
|
||||
suffix = "good."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("slow."):
|
||||
elif endswith(lqname, "slow."):
|
||||
slow = True
|
||||
suffix = "slow."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("8.2.6.0.1.0.0.2.ip6.arpa."):
|
||||
ip6req = True
|
||||
elif endswith(lqname, "8.2.6.0.1.0.0.2.ip6.arpa."):
|
||||
ip6req = True
|
||||
elif endswith(lqname, "a.b.stale."):
|
||||
if lqname == "a.b.stale.":
|
||||
if rrtype == TXT:
|
||||
# Direct query.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "peekaboo"))
|
||||
r.flags |= dns.flags.AA
|
||||
elif rrtype == NS:
|
||||
# NS a.b.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.a.b.stale."))
|
||||
r.additional.append(dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.3"))
|
||||
r.flags |= dns.flags.AA
|
||||
elif rrtype == SOA:
|
||||
# SOA a.b.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"))
|
||||
r.flags |= dns.flags.AA
|
||||
else:
|
||||
# NODATA.
|
||||
r.authority.append(dns.rrset.from_text(lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"))
|
||||
else:
|
||||
r.authority.append(dns.rrset.from_text(lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"))
|
||||
r.set_rcode(NXDOMAIN)
|
||||
# NXDOMAIN.
|
||||
return r
|
||||
else:
|
||||
r.set_rcode(REFUSED)
|
||||
return r
|
||||
|
|
@ -94,15 +123,15 @@ def create_response(msg):
|
|||
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."):
|
||||
elif endswith(lqname, "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):
|
||||
elif endswith("icky.ptang.zoop.boing.", 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 lqname.endswith("zoop.boing."):
|
||||
elif endswith(lqname, "zoop.boing."):
|
||||
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)
|
||||
elif ip6req:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ def logquery(type, qname):
|
|||
with open("qlog", "a") as f:
|
||||
f.write("%s %s\n", type, qname)
|
||||
|
||||
def endswith(domain, labels):
|
||||
return domain.endswith("." + labels) or domain == labels
|
||||
|
||||
############################################################################
|
||||
# Respond to a DNS query.
|
||||
# For good. it serves:
|
||||
|
|
@ -44,6 +47,9 @@ 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 stale. it serves:
|
||||
# a.b.stale. IN TXT hooray (resolver did do qname minimization)
|
||||
############################################################################
|
||||
def create_response(msg):
|
||||
m = dns.message.from_wire(msg)
|
||||
|
|
@ -70,23 +76,59 @@ def create_response(msg):
|
|||
|
||||
ip6req = False
|
||||
|
||||
if lqname.endswith("bad."):
|
||||
if endswith(lqname, "bad."):
|
||||
bad = True
|
||||
suffix = "bad."
|
||||
lqname = lqname[:-4]
|
||||
elif lqname.endswith("ugly."):
|
||||
elif endswith(lqname, "ugly."):
|
||||
ugly = True
|
||||
suffix = "ugly."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("good."):
|
||||
elif endswith(lqname, "good."):
|
||||
suffix = "good."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("slow."):
|
||||
elif endswith(lqname, "slow."):
|
||||
slow = True
|
||||
suffix = "slow."
|
||||
lqname = lqname[:-5]
|
||||
elif lqname.endswith("1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."):
|
||||
elif endswith(lqname, "1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."):
|
||||
ip6req = True
|
||||
elif endswith(lqname, "b.stale."):
|
||||
if lqname == "a.b.stale.":
|
||||
if rrtype == TXT:
|
||||
# Direct query.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, TXT, "hooray"))
|
||||
r.flags |= dns.flags.AA
|
||||
elif rrtype == NS:
|
||||
# NS a.b.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.a.b.stale."))
|
||||
r.additional.append(dns.rrset.from_text("ns.a.b.stale.", 1, IN, A, "10.53.0.3"))
|
||||
r.flags |= dns.flags.AA
|
||||
elif rrtype == SOA:
|
||||
# SOA a.b.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"))
|
||||
r.flags |= dns.flags.AA
|
||||
else:
|
||||
# NODATA.
|
||||
r.authority.append(dns.rrset.from_text(lqname, 1, IN, SOA, "a.b.stale. hostmaster.a.b.stale. 1 2 3 4 5"))
|
||||
elif lqname == "b.stale.":
|
||||
if rrtype == NS:
|
||||
# NS b.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, NS, "ns.b.stale."))
|
||||
r.additional.append(dns.rrset.from_text("ns.b.stale.", 1, IN, A, "10.53.0.4"))
|
||||
r.flags |= dns.flags.AA
|
||||
elif rrtype == SOA:
|
||||
# SOA b.
|
||||
r.answer.append(dns.rrset.from_text(lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"))
|
||||
r.flags |= dns.flags.AA
|
||||
else:
|
||||
# NODATA.
|
||||
r.authority.append(dns.rrset.from_text(lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"))
|
||||
else:
|
||||
r.authority.append(dns.rrset.from_text(lqname, 1, IN, SOA, "b.stale. hostmaster.b.stale. 1 2 3 4 5"))
|
||||
r.set_rcode(NXDOMAIN)
|
||||
# NXDOMAIN.
|
||||
return r
|
||||
else:
|
||||
r.set_rcode(REFUSED)
|
||||
return r
|
||||
|
|
@ -101,9 +143,9 @@ def create_response(msg):
|
|||
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."):
|
||||
elif endswith(lqname, "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):
|
||||
if bad or not endswith("more.icky.icky.icky.ptang.zoop.boing.", lqname):
|
||||
r.set_rcode(NXDOMAIN)
|
||||
if ugly:
|
||||
r.set_rcode(FORMERR)
|
||||
|
|
@ -111,7 +153,7 @@ def create_response(msg):
|
|||
r.flags |= dns.flags.AA
|
||||
if lqname == "test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa." and rrtype == TXT:
|
||||
r.answer.append(dns.rrset.from_text("test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.", 1, IN, TXT, "long_ip6_name"))
|
||||
elif "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.".endswith(lqname):
|
||||
elif endswith("0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.", lqname):
|
||||
#NODATA answer
|
||||
r.authority.append(dns.rrset.from_text("1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, SOA, "ns4.good. hostmaster.arpa. 2018050100 120 30 320 16"))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -33,3 +33,7 @@ ns2.ugly. A 10.53.0.2
|
|||
|
||||
fwd. NS ns2.fwd.
|
||||
ns2.fwd. A 10.53.0.2
|
||||
|
||||
$TTL 2
|
||||
stale. NS ns2.stale.
|
||||
ns2.stale. A 10.53.0.2
|
||||
|
|
|
|||
|
|
@ -392,6 +392,146 @@ grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
|||
# ;; ANSWER SECTION:
|
||||
# test1.test2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa. 1 IN TXT "long_ip6_name"
|
||||
grep 'ip6\.arpa.*TXT.*long_ip6_name' dig.out.test$n > /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`
|
||||
|
||||
# Below are test cases for GL #2665: The QNAME minimization (if enabled) should
|
||||
# also occur on the second query, after the RRsets have expired from cache.
|
||||
# BIND will still have the entries in cache, but marked stale. These stale
|
||||
# entries should not prevent the resolver from minimizing the QNAME.
|
||||
# We query for the test domain a.b.stale. in all cases (QNAME minimization off,
|
||||
# strict mode, and relaxed mode) and expect it to behave the same the second
|
||||
# time when we have a stale delegation structure in cache.
|
||||
n=`expr $n + 1`
|
||||
echo_i "query for .stale is not minimized when qname-minimization is off ($n)"
|
||||
ret=0
|
||||
$CLEANQL
|
||||
$RNDCCMD 10.53.0.5 flush
|
||||
$DIG $DIGOPTS @10.53.0.5 txt a.b.stale. > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "a\.b\.stale\..*1.*IN.*TXT.*peekaboo" dig.out.test$n > /dev/null || ret=1
|
||||
sleep 1
|
||||
echo "TXT a.b.stale." | $DIFF ans2/query.log - > /dev/null || ret=1
|
||||
echo "TXT a.b.stale." | $DIFF ans3/query.log - > /dev/null || ret=1
|
||||
test -f ans4/query.log && 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 .stale is properly minimized when qname-minimization is in strict mode ($n)"
|
||||
ret=0
|
||||
$CLEANQL
|
||||
$RNDCCMD 10.53.0.6 flush
|
||||
$DIG $DIGOPTS @10.53.0.6 txt a.b.stale. > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n > /dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log > ans2/query.log.sorted
|
||||
cat << __EOF | $DIFF ans2/query.log.sorted - > /dev/null || ret=1
|
||||
ADDR ns.b.stale.
|
||||
ADDR ns2.stale.
|
||||
NS b.stale.
|
||||
NS stale.
|
||||
__EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log > ans4/query.log.sorted
|
||||
cat << __EOF | $DIFF ans4/query.log.sorted - > /dev/null || ret=1
|
||||
ADDR ns.b.stale.
|
||||
NS b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
n=`expr $n + 1`
|
||||
echo_i "query for .stale is properly minimized when qname-minimization is in relaxed mode ($n)"
|
||||
ret=0
|
||||
$CLEANQL
|
||||
$RNDCCMD 10.53.0.7 flush
|
||||
$DIG $DIGOPTS @10.53.0.7 txt a.b.stale. > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n > /dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log > ans2/query.log.sorted
|
||||
cat << __EOF | $DIFF ans2/query.log.sorted - > /dev/null || ret=1
|
||||
ADDR _.b.stale.
|
||||
ADDR ns.b.stale.
|
||||
ADDR ns2.stale.
|
||||
__EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log > ans4/query.log.sorted
|
||||
cat << __EOF | $DIFF ans4/query.log.sorted - > /dev/null || ret=1
|
||||
ADDR ns.b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
echo_i "sleep 2, allow entries in cache to go stale"
|
||||
sleep 2
|
||||
|
||||
n=`expr $n + 1`
|
||||
echo_i "query for .stale is not minimized when qname-minimization is off (stale cache) ($n)"
|
||||
ret=0
|
||||
$CLEANQL
|
||||
$DIG $DIGOPTS @10.53.0.5 txt a.b.stale. > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "a\.b\.stale\..*1.*IN.*TXT.*peekaboo" dig.out.test$n > /dev/null || ret=1
|
||||
sleep 1
|
||||
echo "TXT a.b.stale." | $DIFF ans2/query.log - > /dev/null || ret=1
|
||||
echo "TXT a.b.stale." | $DIFF ans3/query.log - > /dev/null || ret=1
|
||||
test -f ans4/query.log && 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 .stale is properly minimized when qname-minimization is in strict mode (stale cache) ($n)"
|
||||
ret=0
|
||||
$CLEANQL
|
||||
$DIG $DIGOPTS @10.53.0.6 txt a.b.stale. > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n > /dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log > ans2/query.log.sorted
|
||||
cat << __EOF | $DIFF ans2/query.log.sorted - > /dev/null || ret=1
|
||||
NS b.stale.
|
||||
NS stale.
|
||||
__EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log > ans4/query.log.sorted
|
||||
cat << __EOF | $DIFF ans4/query.log.sorted - > /dev/null || ret=1
|
||||
NS b.stale.
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
n=`expr $n + 1`
|
||||
echo_i "query for .stale is properly minimized when qname-minimization is in relaxed mode (stale cache) ($n)"
|
||||
ret=0
|
||||
$CLEANQL
|
||||
$DIG $DIGOPTS @10.53.0.7 txt a.b.stale. > dig.out.test$n
|
||||
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
|
||||
grep "a\.b\.stale\..*1.*IN.*TXT.*hooray" dig.out.test$n > /dev/null || ret=1
|
||||
sleep 1
|
||||
sort ans2/query.log > ans2/query.log.sorted
|
||||
cat << __EOF | $DIFF ans2/query.log.sorted - > /dev/null || ret=1
|
||||
ADDR _.b.stale.
|
||||
__EOF
|
||||
test -f ans3/query.log && ret=1
|
||||
sort ans4/query.log > ans4/query.log.sorted
|
||||
cat << __EOF | $DIFF ans4/query.log.sorted - > /dev/null || ret=1
|
||||
TXT a.b.stale.
|
||||
__EOF
|
||||
for ans in ans2 ans3 ans4; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; done
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=`expr $status + $ret`
|
||||
|
||||
echo_i "exit status: $status"
|
||||
[ $status -eq 0 ] || exit 1
|
||||
|
|
|
|||
|
|
@ -82,3 +82,7 @@ Bug Fixes
|
|||
When the affinity is not set, tests show a slight dip in the authoritative
|
||||
performance of around 5% (ranging from 3.8% to 7.8%), but
|
||||
the recursive performance is now consistently improved. :gl:`#2822`
|
||||
|
||||
- When following QNAME minimization, BIND could use a stale zonecut from cache
|
||||
to resolve the query, resulting in a non-minimized query. This has been
|
||||
fixed :gl:`#2665`
|
||||
|
|
|
|||
|
|
@ -3523,7 +3523,9 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
|
|||
for (header = node->data; header != NULL; header = header->next)
|
||||
{
|
||||
if (header->serial <= search->serial &&
|
||||
!IGNORE(header) && EXISTS(header)) {
|
||||
!IGNORE(header) && EXISTS(header) &&
|
||||
!ANCIENT(header))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3582,7 +3584,9 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
|
|||
for (header = wnode->data; header != NULL;
|
||||
header = header->next) {
|
||||
if (header->serial <= search->serial &&
|
||||
!IGNORE(header) && EXISTS(header)) {
|
||||
!IGNORE(header) && EXISTS(header) &&
|
||||
!ANCIENT(header))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -4677,11 +4681,13 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
|
|||
&header_prev)) {
|
||||
/* Do nothing. */
|
||||
} else if (header->type == dns_rdatatype_dname &&
|
||||
EXISTS(header)) {
|
||||
EXISTS(header) && !ANCIENT(header))
|
||||
{
|
||||
dname_header = header;
|
||||
header_prev = header;
|
||||
} else if (header->type == RBTDB_RDATATYPE_SIGDNAME &&
|
||||
EXISTS(header)) {
|
||||
EXISTS(header) && !ANCIENT(header))
|
||||
{
|
||||
sigdname_header = header;
|
||||
header_prev = header;
|
||||
} else {
|
||||
|
|
@ -4751,7 +4757,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
|
|||
if (check_stale_header(node, header, &locktype, lock,
|
||||
search, &header_prev)) {
|
||||
/* Do nothing. */
|
||||
} else if (EXISTS(header)) {
|
||||
} else if (EXISTS(header) && !ANCIENT(header)) {
|
||||
/*
|
||||
* We've found an extant rdataset. See if
|
||||
* we're interested in it.
|
||||
|
|
@ -5357,6 +5363,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
|
|||
} else if (!dcnull) {
|
||||
dns_name_copy(dcname, foundname);
|
||||
}
|
||||
|
||||
/*
|
||||
* We now go looking for an NS rdataset at the node.
|
||||
*/
|
||||
|
|
@ -5372,8 +5379,23 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
|
|||
header_next = header->next;
|
||||
if (check_stale_header(node, header, &locktype, lock, &search,
|
||||
&header_prev)) {
|
||||
/* Do nothing. */
|
||||
} else if (EXISTS(header)) {
|
||||
/*
|
||||
* The function dns_rbt_findnode found us the a matching
|
||||
* node for 'name' and stored the result in 'dcname'.
|
||||
* This is the deepest known zonecut in our database.
|
||||
* However, this node may be stale and if serve-stale
|
||||
* is not enabled (in other words 'stale-answer-enable'
|
||||
* is set to no), this node may not be used as a
|
||||
* zonecut we know about. If so, find the deepest
|
||||
* zonecut from this node up and return that instead.
|
||||
*/
|
||||
NODE_UNLOCK(lock, locktype);
|
||||
result = find_deepest_zonecut(&search, node, nodep,
|
||||
foundname, rdataset,
|
||||
sigrdataset);
|
||||
dns_name_copy(foundname, dcname);
|
||||
goto tree_exit;
|
||||
} else if (EXISTS(header) && !ANCIENT(header)) {
|
||||
/*
|
||||
* If we found a type we were looking for, remember
|
||||
* it.
|
||||
|
|
|
|||
Loading…
Reference in a new issue