From 11add6919855012fb8b41bb0ae6c15d6a6855f6d Mon Sep 17 00:00:00 2001 From: Diego Fronza Date: Fri, 28 Aug 2020 18:49:26 -0300 Subject: [PATCH] Added test for the proposed fix The test works as follows: 1. Client wants to resolve unusual ip6.arpa. name: 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. IN TXT 2. Query is sent to ns7, a qmin enabled resolver. 3. ns7 do the first stage in query minimization for the name and send a new query to root (ns1): _.1.0.0.2.ip6.arpa. IN A 4. ns1 delegates ip6.arpa. to ns2.good.: ;; AUTHORITY SECTION: ;ip6.arpa. 20 IN NS ns2.good. ;; ADDITIONAL SECTION: ;ns2.good. 20 IN A 10.53.0.2 5. ns7 do a second round in minimizing the name and send a new query to ns2.good. (10.53.0.2): _.8.2.6.0.1.0.0.2.ip6.arpa. IN A 6. ans2 delegates 8.2.6.0.1.0.0.2.ip6.arpa. to ns3.good.: ;; AUTHORITY SECTION: ;8.2.6.0.1.0.0.2.ip6.arpa. 60 IN NS ns3.good. ;; ADDITIONAL SECTION: ;ns3.good. 60 IN A 10.53.0.3 7. ns7 do a third round in minimizing the name and send a new query to ns3.good.: _.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa. IN A 8. ans3 delegates 1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa. to ns4.good.: ;; AUTHORITY SECTION: ;1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa. 60 IN NS ns4.good. ;; ADDITIONAL SECTION: ;ns4.good. 60 IN A 10.53.0.4 9. ns7 do fourth round in minimizing the name and send a new query to ns4.good.: _.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa. IN A 10. ns4.good. doesn't know such name, but answers stating it is authoritative for the domai: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 53815 ... ;; AUTHORITY SECTION: 1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa. 60 IN SOA ns4.good. ... 11. ns7 do another minimization on name: _.9.0.9.4.1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa sends to ns4.good. and gets the same SOA response stated in item #10 12. ns7 do another minimization on name: _.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 sends to ns4.good. and gets the same SOA response stated in item #10. 13. ns7 do the last query minimization name for the ip6.arpa. QNAME. After all IPv6 labels are exausted the algorithm falls back to the original QNAME: 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 ns7 sends a new query with the original QNAME to ans4. 14. Finally ans4 answers with the expected response: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40969 ;; flags: qr aa; QUESTION: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 8192 ;; QUESTION 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. IN TXT ;; 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" --- bin/tests/system/qmin/ans2/ans.py | 35 ++++++++++++++++++++----------- bin/tests/system/qmin/ans3/ans.py | 7 +++++++ bin/tests/system/qmin/ans4/ans.py | 15 +++++++++++++ bin/tests/system/qmin/tests.sh | 11 ++++++++++ 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/bin/tests/system/qmin/ans2/ans.py b/bin/tests/system/qmin/ans2/ans.py index c4e9874537..96e723986a 100755 --- a/bin/tests/system/qmin/ans2/ans.py +++ b/bin/tests/system/qmin/ans2/ans.py @@ -48,6 +48,7 @@ def logquery(type, qname): # # 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. +# 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 ############################################################################ @@ -76,33 +77,37 @@ def create_response(msg): if lqname.endswith("1.0.0.2.ip6.arpa."): # Direct query - give direct answer - 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: + if lqname.endswith("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")) + elif 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.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): # 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")) + 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: # NXDOMAIN - 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")) + 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."): 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.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): # NODATA answer - r.authority.append(dns.rrset.from_text("ip6.arpa.", 1, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1")) + r.authority.append(dns.rrset.from_text("ip6.arpa.", 30, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1")) else: # NXDOMAIN - r.authority.append(dns.rrset.from_text("ip6.arpa.", 1, IN, SOA, "ns2.good. hostmaster.arpa. 2018050100 1 1 1 1")) + 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."): @@ -134,19 +139,25 @@ def create_response(msg): 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.answer.append(dns.rrset.from_text(suffix, 30, 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.answer.append(dns.rrset.from_text("ns2."+suffix, 30, 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.answer.append(dns.rrset.from_text("ns2."+suffix, 30, 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.answer.append(dns.rrset.from_text("ns3."+suffix, 30, 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.answer.append(dns.rrset.from_text("ns3."+suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::3")) + r.flags |= dns.flags.AA + elif lqname == "ns4." and rrtype == A: + r.answer.append(dns.rrset.from_text("ns4."+suffix, 30, IN, A, "10.53.0.4")) + r.flags |= dns.flags.AA + elif lqname == "ns4." and rrtype == AAAA: + r.answer.append(dns.rrset.from_text("ns4."+suffix, 30, IN, AAAA, "fd92:7065:b8e:ffff::4")) 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")) diff --git a/bin/tests/system/qmin/ans3/ans.py b/bin/tests/system/qmin/ans3/ans.py index e96d3971fa..9a459d7835 100755 --- a/bin/tests/system/qmin/ans3/ans.py +++ b/bin/tests/system/qmin/ans3/ans.py @@ -67,6 +67,8 @@ def create_response(msg): r = dns.message.make_response(m) r.set_rcode(NOERROR) + ip6req = False + if lqname.endswith("bad."): bad = True suffix = "bad." @@ -82,6 +84,8 @@ def create_response(msg): slow = True suffix = "slow." lqname = lqname[:-5] + elif lqname.endswith("8.2.6.0.1.0.0.2.ip6.arpa."): + ip6req = True else: r.set_rcode(REFUSED) return r @@ -101,6 +105,9 @@ def create_response(msg): elif lqname.endswith("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: + r.authority.append(dns.rrset.from_text("1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa.", 60, IN, NS, "ns4.good.")) + r.additional.append(dns.rrset.from_text("ns4.good.", 60, IN, A, "10.53.0.4")) else: r.set_rcode(REFUSED) diff --git a/bin/tests/system/qmin/ans4/ans.py b/bin/tests/system/qmin/ans4/ans.py index 15c256ba32..a836af43ff 100755 --- a/bin/tests/system/qmin/ans4/ans.py +++ b/bin/tests/system/qmin/ans4/ans.py @@ -68,6 +68,8 @@ def create_response(msg): r = dns.message.make_response(m) r.set_rcode(NOERROR) + ip6req = False + if lqname.endswith("bad."): bad = True suffix = "bad." @@ -83,6 +85,8 @@ def create_response(msg): slow = True suffix = "slow." lqname = lqname[:-5] + elif lqname.endswith("1.1.1.1.8.2.6.0.1.0.0.2.ip6.arpa."): + ip6req = True else: r.set_rcode(REFUSED) return r @@ -103,6 +107,17 @@ def create_response(msg): r.set_rcode(NXDOMAIN) if ugly: r.set_rcode(FORMERR) + elif ip6req: + 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): + #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: + # NXDOMAIN + 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")) + r.set_rcode(NXDOMAIN) else: r.set_rcode(REFUSED) diff --git a/bin/tests/system/qmin/tests.sh b/bin/tests/system/qmin/tests.sh index 59c06e9bbf..ff77d21fd6 100755 --- a/bin/tests/system/qmin/tests.sh +++ b/bin/tests/system/qmin/tests.sh @@ -383,5 +383,16 @@ for ans in ans2; do mv -f $ans/query.log query-$ans-$n.log 2>/dev/null || true; if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` +n=`expr $n + 1` +echo_i "qname minimization resolves unusual ip6.arpa. names ($n)" +ret=0 +$CLEANQL +$DIG $DIGOPTS 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. txt @10.53.0.7 > dig.out.test$n 2>&1 +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +# Expected output in dig.out.test$n: +# ;; 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 + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1