# 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)
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("stale."):
+ if lqname.endswith("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 lqname.endswith("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 lqname.endswith("bad."):
bad = True
suffix = "bad."
# 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)
suffix = "slow."
lqname = lqname[:-5]
elif lqname.endswith("8.2.6.0.1.0.0.2.ip6.arpa."):
- ip6req = True
+ ip6req = True
+ elif lqname.endswith("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
# 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)
lqname = lqname[:-5]
elif lqname.endswith("1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."):
ip6req = True
+ elif lqname.endswith("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
fwd. NS ns2.fwd.
ns2.fwd. A 10.53.0.2
+
+$TTL 2
+stale. NS ns2.stale.
+ns2.stale. A 10.53.0.2
# ;; 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