diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 18:37:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 18:37:14 +0000 |
commit | ea648e70a989cca190cd7403fe892fd2dcc290b4 (patch) | |
tree | e2b6b1c647da68b0d4d66082835e256eb30970e8 /bin/tests/system/chain | |
parent | Initial commit. (diff) | |
download | bind9-upstream.tar.xz bind9-upstream.zip |
Adding upstream version 1:9.11.5.P4+dfsg.upstream/1%9.11.5.P4+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bin/tests/system/chain')
-rw-r--r-- | bin/tests/system/chain/README | 15 | ||||
-rw-r--r-- | bin/tests/system/chain/ans3/ans.pl | 101 | ||||
-rw-r--r-- | bin/tests/system/chain/ans4/README.anspy | 17 | ||||
-rwxr-xr-x | bin/tests/system/chain/ans4/ans.py | 347 | ||||
-rwxr-xr-x | bin/tests/system/chain/clean.sh | 15 | ||||
-rw-r--r-- | bin/tests/system/chain/ns1/named.conf.in | 25 | ||||
-rw-r--r-- | bin/tests/system/chain/ns1/root.db | 45 | ||||
-rw-r--r-- | bin/tests/system/chain/ns2/example.db | 67 | ||||
-rw-r--r-- | bin/tests/system/chain/ns2/generic.db | 17 | ||||
-rw-r--r-- | bin/tests/system/chain/ns2/named.conf.in | 51 | ||||
-rw-r--r-- | bin/tests/system/chain/ns2/sign.sh | 20 | ||||
-rw-r--r-- | bin/tests/system/chain/ns2/sub.db | 24 | ||||
-rw-r--r-- | bin/tests/system/chain/ns5/named.conf.in | 39 | ||||
-rw-r--r-- | bin/tests/system/chain/ns5/sub.db | 24 | ||||
-rw-r--r-- | bin/tests/system/chain/ns7/named.conf.in | 43 | ||||
-rw-r--r-- | bin/tests/system/chain/ns7/root.hint | 12 | ||||
-rw-r--r-- | bin/tests/system/chain/prereq.sh | 50 | ||||
-rw-r--r-- | bin/tests/system/chain/setup.sh | 25 | ||||
-rw-r--r-- | bin/tests/system/chain/tests.sh | 269 |
19 files changed, 1206 insertions, 0 deletions
diff --git a/bin/tests/system/chain/README b/bin/tests/system/chain/README new file mode 100644 index 0000000..f51c123 --- /dev/null +++ b/bin/tests/system/chain/README @@ -0,0 +1,15 @@ +Copyright (C) Internet Systems Consortium, Inc. ("ISC") + +See COPYRIGHT in the source root or http://isc.org/copyright.html for terms. + +ns1 is the root server. + +ns2 and ns5 are both authoritative servers. + +ans3 is a mock authoritative server that can return various broken +responses. + +ans4 is a mock authoritative server that can return CNAME or DNAME +responses of arbitrary size in arbitrary order. + +ns7 is the resolver under test. diff --git a/bin/tests/system/chain/ans3/ans.pl b/bin/tests/system/chain/ans3/ans.pl new file mode 100644 index 0000000..cdbfc84 --- /dev/null +++ b/bin/tests/system/chain/ans3/ans.pl @@ -0,0 +1,101 @@ +#!/usr/bin/env perl +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +use strict; +use warnings; + +use IO::File; +use Getopt::Long; +use Net::DNS::Nameserver; + +my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; +print $pidf "$$\n" or die "cannot write pid file: $!"; +$pidf->close or die "cannot close pid file: $!"; +sub rmpid { unlink "ans.pid"; exit 1; }; + +$SIG{INT} = \&rmpid; +$SIG{TERM} = \&rmpid; + +my $localaddr = "10.53.0.3"; + +my $localport = int($ENV{'PORT'}); +if (!$localport) { $localport = 5300; } + +my $verbose = 0; +my $ttl = 60; +my $zone = "example.broken"; +my $nsname = "ns3.$zone"; +my $synth = "synth-then-dname.$zone"; +my $synth2 = "synth2-then-dname.$zone"; + +sub reply_handler { + my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_; + my ($rcode, @ans, @auth, @add); + + print ("request: $qname/$qtype\n"); + STDOUT->flush(); + + if ($qname eq "example.broken") { + if ($qtype eq "SOA") { + my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0"); + push @ans, $rr; + } elsif ($qtype eq "NS") { + my $rr = new Net::DNS::RR("$qname $ttl $qclass NS $nsname"); + push @ans, $rr; + $rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr"); + push @add, $rr; + } + $rcode = "NOERROR"; + } elsif ($qname eq "cname-to-$synth2") { + my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2"); + push @ans, $rr; + $rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name"); + push @ans, $rr; + $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME ."); + push @ans, $rr; + $rcode = "NOERROR"; + } elsif ($qname eq "$synth" || $qname eq "$synth2") { + if ($qtype eq "DNAME") { + my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME ."); + push @ans, $rr; + } + $rcode = "NOERROR"; + } elsif ($qname eq "name.$synth") { + my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name."); + push @ans, $rr; + $rr = new Net::DNS::RR("$synth $ttl $qclass DNAME ."); + push @ans, $rr; + $rcode = "NOERROR"; + } elsif ($qname eq "name.$synth2") { + my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name."); + push @ans, $rr; + $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME ."); + push @ans, $rr; + $rcode = "NOERROR"; + } else { + $rcode = "REFUSED"; + } + return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); +} + +GetOptions( + 'port=i' => \$localport, + 'verbose!' => \$verbose, +); + +my $ns = Net::DNS::Nameserver->new( + LocalAddr => $localaddr, + LocalPort => $localport, + ReplyHandler => \&reply_handler, + Verbose => $verbose, +); + +$ns->main_loop; diff --git a/bin/tests/system/chain/ans4/README.anspy b/bin/tests/system/chain/ans4/README.anspy new file mode 100644 index 0000000..a419c61 --- /dev/null +++ b/bin/tests/system/chain/ans4/README.anspy @@ -0,0 +1,17 @@ +Copyright (C) Internet Systems Consortium, Inc. ("ISC") + +See COPYRIGHT in the source root or http://isc.org/copyright.html for terms. + +REQUIREMENTS +ans.py requires at least dnspython 1.12.0. + +"ans.py" is a fairly simple Python script that will respond as an +authoritative server to DNS queries. It opens a UDP socket on 10.53.0.4 +and fd92:7065:b8e:ffff::8, port 5300 (or PORT) (these are for DNS queries) +and a TCP socket addresses on 10.53.0.4 at port 5301 (or EXTRAPORT1) +(this is the control channel). + +Please note that all functionality and formatting are subject to change as +we determine what features the tool will need. + +"ans.py" will respond to queries as follows: TBD diff --git a/bin/tests/system/chain/ans4/ans.py b/bin/tests/system/chain/ans4/ans.py new file mode 100755 index 0000000..2dd7def --- /dev/null +++ b/bin/tests/system/chain/ans4/ans.py @@ -0,0 +1,347 @@ +############################################################################ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. +############################################################################ + +############################################################################ +# ans.py: See README.anspy for details. +############################################################################ + +from __future__ import print_function +import os +import sys +import signal +import socket +import select +from datetime import datetime, timedelta +import functools + +import dns, dns.message, dns.query +from dns.rdatatype import * +from dns.rdataclass import * +from dns.rcode import * +from dns.name import * + +############################################################################ +# set up the RRs to be returned in the next answer +# +# the message contains up to two pipe-separated ('|') fields. +# +# the first field of the message is a comma-separated list +# of actions indicating what to put into the answer set +# (e.g., a dname, a cname, another cname, etc) +# +# supported actions: +# - cname (cname from the current name to a new one in the same domain) +# - dname (dname to a new domain, plus a synthesized cname) +# - xname ("external" cname, to a new name in a new domain) +# +# example: xname, dname, cname represents a CNAME to an external +# domain which is then answered by a DNAME and synthesized +# CNAME pointing to yet another domain, which is then answered +# by a CNAME within the same domain, and finally an answer +# to the query. each RR in the answer set has a corresponding +# RRSIG. these signatures are not valid, but will exercise the +# response parser. +# +# the second field is a comma-separated list of which RRs in the +# answer set to include in the answer, in which order. if prepended +# with 's', the number indicates which signature to include. +# +# examples: for the answer set "cname, cname, cname", an rr set +# '1, s1, 2, s2, 3, s3, 4, s4' indicates that all four RRs should +# be included in the answer, with siagntures, in the origninal +# order, while 4, s4, 3, s3, 2, s2, 1, s1' indicates the order +# should be reversed, 's3, s3, s3, s3' indicates that the third +# RRSIG should be repeated four times and everything else should +# be omitted, and so on. +# +# if there is no second field (i.e., no pipe symbol appears in +# the line) , the default is to send all answers and signatures. +# if a pipe symbol exists but the second field is empty, then +# nothing is sent at all. +############################################################################ +actions = [] +rrs = [] +def ctl_channel(msg): + global actions, rrs + + msg = msg.splitlines().pop(0) + print ('received control message: %s' % msg) + + msg = msg.split(b'|') + if len(msg) == 0: + return + + actions = [x.strip() for x in msg[0].split(b',')] + n = functools.reduce(lambda n, act: (n + (2 if act == b'dname' else 1)), [0] + actions) + + if len(msg) == 1: + rrs = [] + for i in range(n): + for b in [False, True]: + rrs.append((i, b)) + return + + rlist = [x.strip() for x in msg[1].split(b',')] + rrs = [] + for item in rlist: + if item[0] == b's'[0]: + i = int(item[1:].strip()) - 1 + if i > n: + print ('invalid index %d' + (i + 1)) + continue + rrs.append((int(item[1:]) - 1, True)) + else: + i = int(item) - 1 + if i > n: + print ('invalid index %d' % (i + 1)) + continue + rrs.append((i, False)) + +############################################################################ +# Respond to a DNS query. +############################################################################ +def create_response(msg): + m = dns.message.from_wire(msg) + qname = m.question[0].name.to_text() + labels = qname.lower().split('.') + wantsigs = True if m.ednsflags & dns.flags.DO else False + + # get qtype + rrtype = m.question[0].rdtype + typename = dns.rdatatype.to_text(rrtype) + + # for 'www.example.com.'... + # - name is 'www' + # - domain is 'example.com.' + # - sld is 'example' + # - tld is 'com.' + name = labels.pop(0) + domain = '.'.join(labels) + sld = labels.pop(0) + tld = '.'.join(labels) + + print ('query: ' + qname + '/' + typename) + print ('domain: ' + domain) + + # default answers, depending on QTYPE. + # currently only A, AAAA, TXT and NS are supported. + ttl = 86400 + additionalA = '10.53.0.4' + additionalAAAA = 'fd92:7065:b8e:ffff::4' + if typename == 'A': + final = '10.53.0.4' + elif typename == 'AAAA': + final = 'fd92:7065:b8e:ffff::4' + elif typename == 'TXT': + final = 'Some\ text\ here' + elif typename == 'NS': + domain = qname + final = ('ns1.%s' % domain) + else: + final = None + + # RRSIG rdata - won't validate but will exercise response parsing + t = datetime.now() + delta = timedelta(30) + t1 = t - delta + t2 = t + delta + inception=t1.strftime('%Y%m%d000000') + expiry=t2.strftime('%Y%m%d000000') + sigdata='OCXH2De0yE4NMTl9UykvOsJ4IBGs/ZIpff2rpaVJrVG7jQfmj50otBAp A0Zo7dpBU4ofv0N/F2Ar6LznCncIojkWptEJIAKA5tHegf/jY39arEpO cevbGp6DKxFhlkLXNcw7k9o7DSw14OaRmgAjXdTFbrl4AiAa0zAttFko Tso=' + + # construct answer set. + answers = [] + sigs = [] + curdom = domain + curname = name + i = 0 + + for action in actions: + if name != 'test': + continue + if action == b'xname': + owner = curname + '.' + curdom + newname = 'cname%d' % i + i += 1 + newdom = 'domain%d.%s' % (i, tld) + i += 1 + target = newname + '.' + newdom + print ('add external CNAME %s to %s' % (owner, target)) + answers.append(dns.rrset.from_text(owner, ttl, IN, CNAME, target)) + rrsig = 'CNAME 5 3 %d %s %s 12345 %s %s' % \ + (ttl, expiry, inception, domain, sigdata) + print ('add external RRISG(CNAME) %s to %s' % (owner, target)) + sigs.append(dns.rrset.from_text(owner, ttl, IN, RRSIG, rrsig)) + curname = newname + curdom = newdom + continue + + if action == b'cname': + owner = curname + '.' + curdom + newname = 'cname%d' % i + target = newname + '.' + curdom + i += 1 + print ('add CNAME %s to %s' % (owner, target)) + answers.append(dns.rrset.from_text(owner, ttl, IN, CNAME, target)) + rrsig = 'CNAME 5 3 %d %s %s 12345 %s %s' % \ + (ttl, expiry, inception, domain, sigdata) + print ('add RRSIG(CNAME) %s to %s' % (owner, target)) + sigs.append(dns.rrset.from_text(owner, ttl, IN, RRSIG, rrsig)) + curname = newname + continue + + if action == b'dname': + owner = curdom + newdom = 'domain%d.%s' % (i, tld) + i += 1 + print ('add DNAME %s to %s' % (owner, newdom)) + answers.append(dns.rrset.from_text(owner, ttl, IN, DNAME, newdom)) + rrsig = 'DNAME 5 3 %d %s %s 12345 %s %s' % \ + (ttl, expiry, inception, domain, sigdata) + print ('add RRSIG(DNAME) %s to %s' % (owner, newdom)) + sigs.append(dns.rrset.from_text(owner, ttl, IN, RRSIG, rrsig)) + owner = curname + '.' + curdom + target = curname + '.' + newdom + print ('add synthesized CNAME %s to %s' % (owner, target)) + answers.append(dns.rrset.from_text(owner, ttl, IN, CNAME, target)) + rrsig = 'CNAME 5 3 %d %s %s 12345 %s %s' % \ + (ttl, expiry, inception, domain, sigdata) + print ('add synthesized RRSIG(CNAME) %s to %s' % (owner, target)) + sigs.append(dns.rrset.from_text(owner, ttl, IN, RRSIG, rrsig)) + curdom = newdom + continue + + # now add the final answer + owner = curname + '.' + curdom + answers.append(dns.rrset.from_text(owner, ttl, IN, rrtype, final)) + rrsig = '%s 5 3 %d %s %s 12345 %s %s' % \ + (typename, ttl, expiry, inception, domain, sigdata) + sigs.append(dns.rrset.from_text(owner, ttl, IN, RRSIG, rrsig)) + + # prepare the response and convert to wire format + r = dns.message.make_response(m) + + if name != 'test': + r.answer.append(answers[-1]) + if wantsigs: + r.answer.append(sigs[-1]) + else: + for (i, sig) in rrs: + if sig and not wantsigs: + continue + elif sig: + r.answer.append(sigs[i]) + else: + r.answer.append(answers[i]) + + if typename != 'NS': + r.authority.append(dns.rrset.from_text(domain, ttl, IN, "NS", + ("ns1.%s" % domain))) + r.additional.append(dns.rrset.from_text(('ns1.%s' % domain), 86400, + IN, A, additionalA)) + r.additional.append(dns.rrset.from_text(('ns1.%s' % domain), 86400, + IN, AAAA, additionalAAAA)) + + r.flags |= dns.flags.AA + r.use_edns() + return r.to_wire() + +def sigterm(signum, frame): + print ("Shutting down now...") + os.remove('ans.pid') + running = False + sys.exit(0) + +############################################################################ +# Main +# +# Set up responder and control channel, open the pid file, and start +# the main loop, listening for queries on the query channel or commands +# on the control channel and acting on them. +############################################################################ +ip4 = "10.53.0.4" +ip6 = "fd92:7065:b8e:ffff::4" + +try: port=int(os.environ['PORT']) +except: port=5300 + +try: ctrlport=int(os.environ['EXTRAPORT1']) +except: ctrlport=5300 + +query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +query4_socket.bind((ip4, port)) + +havev6 = True +try: + query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + try: + query6_socket.bind((ip6, port)) + except: + query6_socket.close() + havev6 = False +except: + havev6 = False + +ctrl_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +ctrl_socket.bind((ip4, ctrlport)) +ctrl_socket.listen(5) + +signal.signal(signal.SIGTERM, sigterm) + +f = open('ans.pid', 'w') +pid = os.getpid() +print (pid, file=f) +f.close() + +running = True + +print ("Listening on %s port %d" % (ip4, port)) +if havev6: + print ("Listening on %s port %d" % (ip6, port)) +print ("Control channel on %s port %d" % (ip4, ctrlport)) +print ("Ctrl-c to quit") + +if havev6: + input = [query4_socket, query6_socket, ctrl_socket] +else: + input = [query4_socket, ctrl_socket] + +while running: + try: + inputready, outputready, exceptready = select.select(input, [], []) + except select.error as e: + break + except socket.error as e: + break + except KeyboardInterrupt: + break + + for s in inputready: + if s == ctrl_socket: + # Handle control channel input + conn, addr = s.accept() + print ("Control channel connected") + while True: + msg = conn.recv(65535) + if not msg: + break + ctl_channel(msg) + conn.close() + if s == query4_socket or s == query6_socket: + print ("Query received on %s" % + (ip4 if s == query4_socket else ip6)) + # Handle incoming queries + msg = s.recvfrom(65535) + rsp = create_response(msg[0]) + if rsp: + s.sendto(rsp, msg[1]) + if not running: + break diff --git a/bin/tests/system/chain/clean.sh b/bin/tests/system/chain/clean.sh new file mode 100755 index 0000000..265123f --- /dev/null +++ b/bin/tests/system/chain/clean.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +rm -f dig.out.* named*.pid +rm -f ns*/named.conf +rm -f */named.memstats */named.recursing */named.lock */named.run */ans.run +rm -f ns2/K* ns2/dsset-* ns2/example.db.signed diff --git a/bin/tests/system/chain/ns1/named.conf.in b/bin/tests/system/chain/ns1/named.conf.in new file mode 100644 index 0000000..5815c3c --- /dev/null +++ b/bin/tests/system/chain/ns1/named.conf.in @@ -0,0 +1,25 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify yes; + dnssec-enable yes; +}; + +zone "." { type master; file "root.db"; }; diff --git a/bin/tests/system/chain/ns1/root.db b/bin/tests/system/chain/ns1/root.db new file mode 100644 index 0000000..bc70f8c --- /dev/null +++ b/bin/tests/system/chain/ns1/root.db @@ -0,0 +1,45 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +. IN SOA root.domain.nil a.root.servers.nil. ( + 2016012800 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum + ) +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 + +example. NS ns2.example. +ns2.example. A 10.53.0.2 + +example.broken. NS ns3.example.broken. +ns3.example.broken. A 10.53.0.3 + +domain0.nil. NS ns2.domain0.nil +domain1.nil. NS ns2.domain0.nil +domain2.nil. NS ns2.domain0.nil +domain3.nil. NS ns2.domain0.nil +domain4.nil. NS ns2.domain0.nil +domain5.nil. NS ns2.domain0.nil +domain6.nil. NS ns2.domain0.nil +domain7.nil. NS ns2.domain0.nil +domain8.nil. NS ns2.domain0.nil +domain9.nil. NS ns2.domain0.nil +ns2.domain0.nil. A 10.53.0.2 +ns2.domain0.nil. AAAA fd92:7065:b8e:ffff::2 + +domain.nil. NS ns4.domain.nil +ns4.domain.nil. A 10.53.0.4 +ns4.domain.nil. AAAA fd92:7065:b8e:ffff::4 + +domain. NS ns4.domain. +ns4.domain. A 10.53.0.4 diff --git a/bin/tests/system/chain/ns2/example.db b/bin/tests/system/chain/ns2/example.db new file mode 100644 index 0000000..5f29f86 --- /dev/null +++ b/bin/tests/system/chain/ns2/example.db @@ -0,0 +1,67 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns2 +ns2 A 10.53.0.2 + +a.short A 10.0.0.1 +short-dname DNAME short +a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 +long-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong +toolong-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong +cname CNAME a.cnamedname +cnamedname DNAME target +a.target A 10.0.0.3 + +; CNAME to delegation +; (unsigned delegations, external and internal) +sub5 NS ns5.sub5 +ns5.sub5 A 10.53.0.5 +a CNAME a.sub5 +sub2 NS ns2.sub2 +ns2.sub2 A 10.53.0.2 +b CNAME b.sub2 + +; (signed delegation, external and internal) +; note: these DS records are fake and will not validate; we're only +; testing that the resolver handles their presence in a reply correctly +signed-sub5 NS ns5.sub5 +signed-sub5 DS 44137 8 2 1CB4F54E0B4F4F85109143113A3C679716A2377D86EB0907846A03FB 0C0A3927 +c CNAME c.signed-sub5 +signed-sub2 NS ns2.sub2 +signed-sub2 DS 44137 8 2 1CB4F54E0B4F4F85109143113A3C679716A2377D86EB0907846A03FB 0C0A3927 +d CNAME d.signed-sub2 + +; long CNAME loop +loop CNAME goop +goop CNAME boop +boop CNAME soup +soup CNAME gump +gump CNAME bump +bump CNAME lump +lump CNAME rump +rump CNAME romp +romp CNAME bomp +bomp CNAME stomp +stomp CNAME clomp +clomp CNAME clump +clump CNAME hunk +hunk CNAME hank +hank CNAME bank +bank CNAME wank +wank CNAME woop +woop CNAME loop diff --git a/bin/tests/system/chain/ns2/generic.db b/bin/tests/system/chain/ns2/generic.db new file mode 100644 index 0000000..60568dd --- /dev/null +++ b/bin/tests/system/chain/ns2/generic.db @@ -0,0 +1,17 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +@ 86400 SOA ns2.nil. hostmaster.ns2.nil. 0 1 1 1 1 +@ 86400 NS ns2.nil. +ns2 86400 A 10.53.0.2 + +@ 86400 A 1.2.3.4 +@ 86400 AAAA 1:2:3::4 +* 86400 A 1.2.3.4 +* 86400 AAAA 1:2:3::4 diff --git a/bin/tests/system/chain/ns2/named.conf.in b/bin/tests/system/chain/ns2/named.conf.in new file mode 100644 index 0000000..519bfb3 --- /dev/null +++ b/bin/tests/system/chain/ns2/named.conf.in @@ -0,0 +1,51 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// NS2 + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "example" { + type master; + file "example.db.signed"; + allow-update { any; }; +}; + +zone "sub2.example" { + type master; + file "sub.db"; +}; + +zone "signed-sub2.example" { + type master; + file "sub.db"; +}; + +zone "domain0.nil" { type master; file "generic.db"; }; +zone "domain1.nil" { type master; file "generic.db"; }; +zone "domain2.nil" { type master; file "generic.db"; }; +zone "domain3.nil" { type master; file "generic.db"; }; +zone "domain4.nil" { type master; file "generic.db"; }; +zone "domain5.nil" { type master; file "generic.db"; }; +zone "domain6.nil" { type master; file "generic.db"; }; +zone "domain7.nil" { type master; file "generic.db"; }; +zone "domain8.nil" { type master; file "generic.db"; }; +zone "domain9.nil" { type master; file "generic.db"; }; diff --git a/bin/tests/system/chain/ns2/sign.sh b/bin/tests/system/chain/ns2/sign.sh new file mode 100644 index 0000000..11b87ad --- /dev/null +++ b/bin/tests/system/chain/ns2/sign.sh @@ -0,0 +1,20 @@ +#!/bin/sh -e +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +SYSTEMTESTTOP=../.. +. $SYSTEMTESTTOP/conf.sh + +zone=example. +zonefile=example.db + +ksk=`$KEYGEN -q -a RSASHA256 -b 2048 -fk -r $RANDFILE $zone` +zsk=`$KEYGEN -q -a RSASHA256 -b 1024 -r $RANDFILE $zone` +$SIGNER -S -r $RANDFILE -o $zone example.db > /dev/null 2>&1 diff --git a/bin/tests/system/chain/ns2/sub.db b/bin/tests/system/chain/ns2/sub.db new file mode 100644 index 0000000..5e65fdf --- /dev/null +++ b/bin/tests/system/chain/ns2/sub.db @@ -0,0 +1,24 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2017031001 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns2 +ns2 A 10.53.0.2 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 +d A 10.0.0.4 diff --git a/bin/tests/system/chain/ns5/named.conf.in b/bin/tests/system/chain/ns5/named.conf.in new file mode 100644 index 0000000..d6813b6 --- /dev/null +++ b/bin/tests/system/chain/ns5/named.conf.in @@ -0,0 +1,39 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// NS2 + +options { + query-source address 10.53.0.5; + notify-source 10.53.0.5; + transfer-source 10.53.0.5; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.5; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type hint; + file "../../common/root.hint"; +}; + +zone "sub5.example" { + type master; + file "sub.db"; +}; + +zone "signed-sub5.example" { + type master; + file "sub.db"; +}; diff --git a/bin/tests/system/chain/ns5/sub.db b/bin/tests/system/chain/ns5/sub.db new file mode 100644 index 0000000..9ddb431 --- /dev/null +++ b/bin/tests/system/chain/ns5/sub.db @@ -0,0 +1,24 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2017031001 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns5 +ns5 A 10.53.0.5 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 +d A 10.0.0.4 diff --git a/bin/tests/system/chain/ns7/named.conf.in b/bin/tests/system/chain/ns7/named.conf.in new file mode 100644 index 0000000..c314922 --- /dev/null +++ b/bin/tests/system/chain/ns7/named.conf.in @@ -0,0 +1,43 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +options { + directory "."; + query-source address 10.53.0.7; + notify-source 10.53.0.7; + transfer-source 10.53.0.7; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.7; }; + listen-on-v6 { fd92:7065:b8e:ffff::7; }; + recursion yes; + allow-recursion { any; }; + dnssec-validation yes; + deny-answer-aliases { + "example"; + } except-from { + "example"; + }; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-sha256; +}; + +controls { + inet 10.53.0.7 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; + +zone "." { + type hint; + file "root.hint"; +}; diff --git a/bin/tests/system/chain/ns7/root.hint b/bin/tests/system/chain/ns7/root.hint new file mode 100644 index 0000000..ab755ba --- /dev/null +++ b/bin/tests/system/chain/ns7/root.hint @@ -0,0 +1,12 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 999999 +. IN NS a.root-servers.nil. +a.root-servers.nil. IN A 10.53.0.1 diff --git a/bin/tests/system/chain/prereq.sh b/bin/tests/system/chain/prereq.sh new file mode 100644 index 0000000..f3f1939 --- /dev/null +++ b/bin/tests/system/chain/prereq.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +$SHELL ../testcrypto.sh || exit 255 + +if test -n "$PYTHON" +then + if $PYTHON -c "import dns" 2> /dev/null + then + : + else + echo_i "This test requires the dnspython module." >&2 + exit 1 + fi +else + echo_i "This test requires Python and the dnspython module." >&2 + exit 1 +fi + +if $PERL -e 'use Net::DNS;' 2>/dev/null +then + if $PERL -e 'use Net::DNS; die if ($Net::DNS::VERSION >= 0.69 && $Net::DNS::VERSION <= 0.74);' 2>/dev/null + then + : + else + echo_i "Net::DNS versions 0.69 to 0.74 have bugs that cause this test to fail: please update." >&2 + exit 1 + fi +else + echo_i "This test requires the perl Net::DNS library." >&2 + exit 1 +fi +if $PERL -e 'use Net::DNS::Nameserver;' 2>/dev/null +then + : +else + echo_i "This test requires the Net::DNS::Nameserver library." >&2 + exit 1 +fi diff --git a/bin/tests/system/chain/setup.sh b/bin/tests/system/chain/setup.sh new file mode 100644 index 0000000..c2b0d69 --- /dev/null +++ b/bin/tests/system/chain/setup.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +$SHELL clean.sh + +test -r $RANDFILE || $GENRANDOM 400 $RANDFILE + +copy_setports ns1/named.conf.in ns1/named.conf +copy_setports ns2/named.conf.in ns2/named.conf +copy_setports ns5/named.conf.in ns5/named.conf +copy_setports ns7/named.conf.in ns7/named.conf + +cd ns2 +$SHELL sign.sh diff --git a/bin/tests/system/chain/tests.sh b/bin/tests/system/chain/tests.sh new file mode 100644 index 0000000..e7ad91e --- /dev/null +++ b/bin/tests/system/chain/tests.sh @@ -0,0 +1,269 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +DIGOPTS="-p ${PORT}" +RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" +SEND="$PERL $SYSTEMTESTTOP/send.pl 10.53.0.4 ${EXTRAPORT1}" +status=0 +n=0 + +n=`expr $n + 1` +echo_i "checking short DNAME from authoritative ($n)" +ret=0 +$DIG $DIGOPTS a.short-dname.example @10.53.0.2 a > dig.out.ns2.short || ret=1 +grep "status: NOERROR" dig.out.ns2.short > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking short DNAME from recursive ($n)" +ret=0 +$DIG $DIGOPTS a.short-dname.example @10.53.0.7 a > dig.out.ns4.short || ret=1 +grep "status: NOERROR" dig.out.ns4.short > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking long DNAME from authoritative ($n)" +ret=0 +$DIG $DIGOPTS a.long-dname.example @10.53.0.2 a > dig.out.ns2.long || ret=1 +grep "status: NOERROR" dig.out.ns2.long > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking long DNAME from recursive ($n)" +ret=0 +$DIG $DIGOPTS a.long-dname.example @10.53.0.7 a > dig.out.ns4.long || ret=1 +grep "status: NOERROR" dig.out.ns4.long > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking (too) long DNAME from authoritative ($n)" +ret=0 +$DIG $DIGOPTS 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.2 a > dig.out.ns2.toolong || ret=1 +grep "status: YXDOMAIN" dig.out.ns2.toolong > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking (too) long DNAME from recursive with cached DNAME ($n)" +ret=0 +$DIG $DIGOPTS 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.7 a > dig.out.ns4.cachedtoolong || ret=1 +grep "status: YXDOMAIN" dig.out.ns4.cachedtoolong > /dev/null || ret=1 +grep '^long-dname\.example\..*DNAME.*long' dig.out.ns4.cachedtoolong > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking (too) long DNAME from recursive without cached DNAME ($n)" +ret=0 +$DIG $DIGOPTS 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglong.toolong-dname.example @10.53.0.7 a > dig.out.ns4.uncachedtoolong || ret=1 +grep "status: YXDOMAIN" dig.out.ns4.uncachedtoolong > /dev/null || ret=1 +grep '^toolong-dname\.example\..*DNAME.*long' dig.out.ns4.uncachedtoolong > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME to DNAME from authoritative ($n)" +ret=0 +$DIG $DIGOPTS cname.example @10.53.0.2 a > dig.out.ns2.cname +grep "status: NOERROR" dig.out.ns2.cname > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME to DNAME from recursive" +ret=0 +$DIG $DIGOPTS cname.example @10.53.0.7 a > dig.out.ns4.cname +grep "status: NOERROR" dig.out.ns4.cname > /dev/null || ret=1 +grep '^cname.example.' dig.out.ns4.cname > /dev/null || ret=1 +grep '^cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 +grep '^a.cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 +grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking DNAME is returned with synthesized CNAME before DNAME ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 name.synth-then-dname.example.broken A > dig.out.test$n +grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 +grep '^name.synth-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 +grep '^synth-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking DNAME is returned with CNAME to synthesized CNAME before DNAME ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 cname-to-synth2-then-dname.example.broken A > dig.out.test$n +grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 +grep '^cname-to-synth2-then-dname\.example\.broken\..*CNAME.*name\.synth2-then-dname\.example\.broken.$' dig.out.test$n > /dev/null || ret=1 +grep '^name\.synth2-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 +grep '^synth2-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME loops are detected ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 loop.example > dig.out.test$n +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +grep "ANSWER: 17" dig.out.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME to external delegated zones is handled ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 a.example > dig.out.test$n +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +grep "ANSWER: 2" dig.out.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME to internal delegated zones is handled ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 b.example > dig.out.test$n +grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 +grep "ANSWER: 2" dig.out.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME to signed external delgation is handled ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 c.example > dig.out.$n +grep "status: NOERROR" dig.out.$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i " failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME to signed internal delgation is handled ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 d.example > dig.out.$n +grep "status: NOERROR" dig.out.$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i " failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking CNAME chains in various orders ($n)" +ret=0 +echo "cname,cname,cname|1,2,3,4,s1,s2,s3,s4" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 +grep 'status: NOERROR' dig.out.1.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.1.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "cname,cname,cname|1,1,2,2,3,4,s4,s3,s1" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.2.$n 2>&1 +grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.2.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "cname,cname,cname|2,1,3,4,s3,s1,s2,s4" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.3.$n 2>&1 +grep 'status: NOERROR' dig.out.3.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.3.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "cname,cname,cname|4,3,2,1,s4,s3,s2,s1" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.4.$n 2>&1 +grep 'status: NOERROR' dig.out.4.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.4.$n > /dev/null 2>&1 || ret=1 +echo "cname,cname,cname|4,3,2,1,s4,s3,s2,s1" | $SEND +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.5.$n 2>&1 +grep 'status: NOERROR' dig.out.5.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.5.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "cname,cname,cname|4,3,3,3,s1,s1,1,3,4" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.6.$n 2>&1 +grep 'status: NOERROR' dig.out.6.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.6.$n > /dev/null 2>&1 || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking that only the initial CNAME is cached ($n)" +ret=0 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "cname,cname,cname|1,2,3,4,s1,s2,s3,s4" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 +sleep 1 +$DIG $DIGOPTS +noall +answer @10.53.0.7 cname1.domain.nil > dig.out.2.$n 2>&1 +ttl=`awk '{print $2}' dig.out.2.$n` +[ "$ttl" -eq 86400 ] || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking DNAME chains in various orders ($n)" +ret=0 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "dname,dname|5,4,3,2,1,s5,s4,s3,s2,s1" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 +grep 'status: NOERROR' dig.out.1.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 3' dig.out.1.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "dname,dname|5,4,3,2,1,s5,s4,s3,s2,s1" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.2.$n 2>&1 +grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 3' dig.out.2.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "dname,dname|2,3,s1,s2,s3,s4,1" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.3.$n 2>&1 +grep 'status: NOERROR' dig.out.3.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 3' dig.out.3.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking external CNAME/DNAME chains in various orders ($n)" +ret=0 +echo "xname,dname|1,2,3,4,s1,s2,s3,s4" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.1.$n 2>&1 +grep 'status: NOERROR' dig.out.1.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.1.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "xname,dname|s2,2,s1,1,4,s4,3" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.2.$n 2>&1 +grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1 +grep 'ANSWER: 2' dig.out.2.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +echo "xname,dname|s2,2,2,2" | $SEND +$DIG $DIGOPTS @10.53.0.7 test.domain.nil > dig.out.3.$n 2>&1 +grep 'status: SERVFAIL' dig.out.3.$n > /dev/null 2>&1 || ret=1 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking explicit DNAME query ($n)" +ret=0 +$DIG $DIGOPTS @10.53.0.7 dname short-dname.example > dig.out.7.$n 2>&1 +grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking DNAME via ANY query ($n)" +ret=0 +$RNDCCMD 10.53.0.7 flush 2>&1 | sed 's/^/ns7 /' | cat_i +$DIG $DIGOPTS @10.53.0.7 any short-dname.example > dig.out.7.$n 2>&1 +grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +echo_i "exit status: $status" +[ $status -eq 0 ] || exit 1 |