diff options
Diffstat (limited to '')
-rw-r--r-- | bin/tests/system/digdelv/ans4/startme | 1 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ans5/ans.pl | 176 | ||||
-rwxr-xr-x | bin/tests/system/digdelv/ans6/ans.pl | 84 | ||||
-rwxr-xr-x | bin/tests/system/digdelv/ans7/ans.pl | 68 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ans8/ans.py | 202 | ||||
-rw-r--r-- | bin/tests/system/digdelv/clean.sh | 35 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ns1/named.conf.in | 30 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ns1/root.db | 26 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ns2/example.db.in | 51 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ns2/named.conf.in | 34 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ns2/sign.sh | 29 | ||||
-rw-r--r-- | bin/tests/system/digdelv/ns3/named.conf.in | 28 | ||||
-rw-r--r-- | bin/tests/system/digdelv/setup.sh | 23 | ||||
-rw-r--r-- | bin/tests/system/digdelv/tests.sh | 1403 | ||||
-rw-r--r-- | bin/tests/system/digdelv/tests_sh_digdelv.py | 14 | ||||
-rw-r--r-- | bin/tests/system/digdelv/yamlget.py | 35 |
16 files changed, 2239 insertions, 0 deletions
diff --git a/bin/tests/system/digdelv/ans4/startme b/bin/tests/system/digdelv/ans4/startme new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/bin/tests/system/digdelv/ans4/startme @@ -0,0 +1 @@ + diff --git a/bin/tests/system/digdelv/ans5/ans.pl b/bin/tests/system/digdelv/ans5/ans.pl new file mode 100644 index 0000000..6396406 --- /dev/null +++ b/bin/tests/system/digdelv/ans5/ans.pl @@ -0,0 +1,176 @@ +#!/usr/bin/perl + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# This is a TCP-only DNS server whose aim is to facilitate testing how dig +# copes with prematurely closed TCP connections. +# +# This server can be configured (through a separate control socket) with a +# series of responses to send for subsequent incoming TCP DNS queries. Only +# one query is handled before closing each connection. In order to keep things +# simple, the server is not equipped with any mechanism for handling malformed +# queries. +# +# Available response types are defined in the %response_types hash in the +# getAnswerSection() function below. Each RR returned is generated dynamically +# based on the QNAME found in the incoming query. + +use IO::File; +use Net::DNS; +use Net::DNS::Packet; + +use strict; + +# Ignore SIGPIPE so we won't fail if peer closes a TCP socket early +local $SIG{PIPE} = 'IGNORE'; + +# Flush logged output after every line +local $| = 1; + +my $server_addr = "10.53.0.5"; +if (@ARGV > 0) { + $server_addr = @ARGV[0]; +} + +my $mainport = int($ENV{'PORT'}); +if (!$mainport) { $mainport = 5300; } +my $ctrlport = int($ENV{'EXTRAPORT1'}); +if (!$ctrlport) { $ctrlport = 5301; } + +my $ctlsock = IO::Socket::INET->new(LocalAddr => "$server_addr", + LocalPort => $ctrlport, Proto => "tcp", Listen => 5, Reuse => 1) or die "$!"; + +my $tcpsock = IO::Socket::INET->new(LocalAddr => "$server_addr", + LocalPort => $mainport, Proto => "tcp", Listen => 5, Reuse => 1) or die "$!"; + +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 @response_sequence = ("complete_axfr"); +my $connection_counter = 0; + +# Return the next answer type to send, incrementing the connection counter and +# making sure the latter does not exceed the size of the array holding the +# configured response sequence. +sub getNextResponseType { + my $response_type = $response_sequence[$connection_counter]; + + $connection_counter++; + $connection_counter %= scalar(@response_sequence); + + return $response_type; +} + +# Return an array of resource records comprising the answer section of a given +# response type. +sub getAnswerSection { + my ($response_type, $qname) = @_; + + my %response_types = ( + no_response => [], + + partial_axfr => [ + Net::DNS::RR->new("$qname 300 IN SOA . . 0 0 0 0 300"), + Net::DNS::RR->new("$qname NS ."), + ], + + complete_axfr => [ + Net::DNS::RR->new("$qname 300 IN SOA . . 0 0 0 0 300"), + Net::DNS::RR->new("$qname NS ."), + Net::DNS::RR->new("$qname 300 IN SOA . . 0 0 0 0 300"), + ], + ); + + return $response_types{$response_type}; +} + + +# Generate a Net::DNS::Packet containing the response to send on the current +# TCP connection. If the answer section of the response is determined to be +# empty, no data will be sent on the connection at all (immediate EOF). +sub generateResponse { + my ($buf) = @_; + my $request; + + if ($Net::DNS::VERSION > 0.68) { + $request = new Net::DNS::Packet(\$buf, 0); + $@ and die $@; + } else { + my $err; + ($request, $err) = new Net::DNS::Packet(\$buf, 0); + $err and die $err; + } + + my @questions = $request->question; + my $qname = $questions[0]->qname; + my $qtype = $questions[0]->qtype; + my $qclass = $questions[0]->qclass; + my $id = $request->header->id; + + my $packet = new Net::DNS::Packet($qname, $qtype, $qclass); + $packet->header->qr(1); + $packet->header->aa(1); + $packet->header->id($id); + + my $response_type = getNextResponseType(); + my $answers = getAnswerSection($response_type, $qname); + for my $rr (@$answers) { + $packet->push("answer", $rr); + } + + print " Sending \"$response_type\" response\n"; + + return $packet->data if @$answers; +} + +my $rin; +my $rout; +for (;;) { + $rin = ''; + vec($rin, fileno($ctlsock), 1) = 1; + vec($rin, fileno($tcpsock), 1) = 1; + + select($rout = $rin, undef, undef, undef); + + if (vec($rout, fileno($ctlsock), 1)) { + my $conn = $ctlsock->accept; + @response_sequence = split(' ', $conn->getline); + $connection_counter = 0; + print "Response sequence set to: @response_sequence\n"; + $conn->close; + } elsif (vec($rout, fileno($tcpsock), 1)) { + my $buf; + my $lenbuf; + my $conn = $tcpsock->accept; + my $n = $conn->sysread($lenbuf, 2); + die unless $n == 2; + my $len = unpack("n", $lenbuf); + $n = $conn->sysread($buf, $len); + die unless $n == $len; + print "TCP request\n"; + my $response = generateResponse($buf); + if ($response) { + $len = length($response); + $n = $conn->syswrite(pack("n", $len), 2); + $n = $conn->syswrite($response, $len); + print " Sent: $n chars via TCP\n"; + } else { + print " No response sent\n"; + } + $conn->close; + } +} diff --git a/bin/tests/system/digdelv/ans6/ans.pl b/bin/tests/system/digdelv/ans6/ans.pl new file mode 100755 index 0000000..39d02b2 --- /dev/null +++ b/bin/tests/system/digdelv/ans6/ans.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl -w + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +use IO::File; +use IO::Socket; +use Net::DNS; +use Net::DNS::Packet; + +my $localport = int($ENV{'PORT'}); +if (!$localport) { $localport = 5300; } + +my $sock = IO::Socket::INET->new(LocalAddr => "10.53.0.6", + LocalPort => $localport, Proto => "udp") or die "$!"; + +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; + +for (;;) { + $sock->recv($buf, 512); + + print "**** request from " , $sock->peerhost, " port ", $sock->peerport, "\n"; + + my $packet; + + if ($Net::DNS::VERSION > 0.68) { + $packet = new Net::DNS::Packet(\$buf, 0); + $@ and die $@; + } else { + my $err; + ($packet, $err) = new Net::DNS::Packet(\$buf, 0); + $err and die $err; + } + + print "REQUEST:\n"; + $packet->print; + + $packet->header->qr(1); + + my @questions = $packet->question; + my $qname = $questions[0]->qname; + my $qtype = $questions[0]->qtype; + + my $donotrespond = 0; + + $packet->header->aa(1); + if ($qtype eq "A") { + $packet->push("answer", + new Net::DNS::RR($qname . " 300 A 10.53.0.5")); + } else { + $donotrespond = 1; + } + + if ($donotrespond == 0) { + my $sendsock = + IO::Socket::INET->new(LocalAddr => "10.53.1.2", + PeerAddr => $sock->peerhost, + PeerPort => $sock->peerport, + Proto => "udp") or die "$!"; + print "**** response from ", $sendsock->sockhost, " to " , + $sendsock->peerhost, " port ", $sendsock->peerport, "\n"; + $sendsock->send($packet->data); + $sendsock->close; + print "RESPONSE:\n"; + $packet->print; + print "\n"; + } else { + print "DROP:\n"; + } +} diff --git a/bin/tests/system/digdelv/ans7/ans.pl b/bin/tests/system/digdelv/ans7/ans.pl new file mode 100755 index 0000000..a7aa60e --- /dev/null +++ b/bin/tests/system/digdelv/ans7/ans.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl -w + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +use IO::File; +use IO::Socket; +use Net::DNS; +use Net::DNS::Packet; + +my $localport = int($ENV{'PORT'}); +if (!$localport) { $localport = 5300; } + +my $sock = IO::Socket::INET->new(LocalAddr => "10.53.0.7", + LocalPort => $localport, Proto => "udp") or die "$!"; + +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; + +STDOUT->autoflush(1); + +print "Net::DNS::VERSION => $Net::DNS::VERSION\n"; + +for (;;) { + $sock->recv($buf, 512); + + print "**** request from " , $sock->peerhost, " port ", $sock->peerport, "\n"; + + my $packet; + + if ($Net::DNS::VERSION > 0.68) { + $packet = new Net::DNS::Packet(\$buf, 0); + $@ and die $@; + } else { + my $err; + ($packet, $err) = new Net::DNS::Packet(\$buf, 0); + $err and die $err; + } + + print "REQUEST:\n"; + $packet->print; + + $packet->header->qr(1); + $packet->header->opcode(5); + + my @questions = $packet->question; + my $qname = $questions[0]->qname; + my $qtype = $questions[0]->qtype; + $packet->push("update", rr_del("$qname SOA")); + + print "RESPONSE:\n"; + $packet->print; + + $sock->send($packet->data); +} diff --git a/bin/tests/system/digdelv/ans8/ans.py b/bin/tests/system/digdelv/ans8/ans.py new file mode 100644 index 0000000..3e18edc --- /dev/null +++ b/bin/tests/system/digdelv/ans8/ans.py @@ -0,0 +1,202 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from __future__ import print_function +import os +import sys +import signal +import socket +import select +import struct + +import dns, dns.message +from dns.rcode import * + +modes = [ + b"silent", # Do not respond + b"close", # UDP: same as silent; TCP: also close the connection + b"servfail", # Always respond with SERVFAIL + b"unstable", # Constantly switch between "silent" and "servfail" +] +mode = modes[0] +n = 0 + + +def ctrl_channel(msg): + global modes, mode, n + + msg = msg.splitlines().pop(0) + print("Received control message: %s" % msg) + + if msg in modes: + mode = msg + n = 0 + print("New mode: %s" % str(mode)) + + +def create_servfail(msg): + m = dns.message.from_wire(msg) + qname = m.question[0].name.to_text() + rrtype = m.question[0].rdtype + typename = dns.rdatatype.to_text(rrtype) + + with open("query.log", "a") as f: + f.write("%s %s\n" % (typename, qname)) + print("%s %s" % (typename, qname), end=" ") + + r = dns.message.make_response(m) + r.set_rcode(SERVFAIL) + return r + + +def sigterm(signum, frame): + print("Shutting down now...") + os.remove("ans.pid") + running = False + sys.exit(0) + + +ip4 = "10.53.0.8" + +try: + port = int(os.environ["PORT"]) +except: + port = 5300 + +try: + ctrlport = int(os.environ["EXTRAPORT1"]) +except: + ctrlport = 5300 + +query4_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +query4_udp.bind((ip4, port)) + +query4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +query4_tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +query4_tcp.bind((ip4, port)) +query4_tcp.listen(100) + +ctrl4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +ctrl4_tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +ctrl4_tcp.bind((ip4, ctrlport)) +ctrl4_tcp.listen(100) + +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)) +print("Listening on %s port %d" % (ip4, ctrlport)) +print("Ctrl-c to quit") + +input = [query4_udp, query4_tcp, ctrl4_tcp] + +hung_conns = [] + +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 == query4_udp: + n = n + 1 + print("UDP query received on %s" % ip4, end=" ") + msg = s.recvfrom(65535) + if ( + mode == b"silent" + or mode == b"close" + or (mode == b"unstable" and n % 2 == 1) + ): + # Do not respond. + print("NO RESPONSE (%s)" % str(mode)) + continue + elif mode == b"servfail" or (mode == b"unstable" and n % 2 == 0): + rsp = create_servfail(msg[0]) + if rsp: + print(dns.rcode.to_text(rsp.rcode())) + s.sendto(rsp.to_wire(), msg[1]) + else: + print("NO RESPONSE (can not create a response)") + else: + raise (Exception("unsupported mode: %s" % mode)) + elif s == query4_tcp: + n = n + 1 + print("TCP query received on %s" % ip4, end=" ") + conn = None + try: + if mode == b"silent" or (mode == b"unstable" and n % 2 == 1): + conn, addr = s.accept() + # Do not respond and hang the connection. + print("NO RESPONSE (%s)" % str(mode)) + hung_conns.append(conn) + continue + elif mode == b"close": + conn, addr = s.accept() + # Do not respond and close the connection. + print("NO RESPONSE (%s)" % str(mode)) + conn.close() + continue + elif mode == b"servfail" or (mode == b"unstable" and n % 2 == 0): + conn, addr = s.accept() + # get TCP message length + msg = conn.recv(2) + if len(msg) != 2: + print("NO RESPONSE (can not read the message length)") + conn.close() + continue + length = struct.unpack(">H", msg[:2])[0] + msg = conn.recv(length) + if len(msg) != length: + print("NO RESPONSE (can not read the message)") + conn.close() + continue + rsp = create_servfail(msg) + if rsp: + print(dns.rcode.to_text(rsp.rcode())) + wire = rsp.to_wire() + conn.send(struct.pack(">H", len(wire))) + conn.send(wire) + else: + print("NO RESPONSE (can not create a response)") + else: + raise (Exception("unsupported mode: %s" % mode)) + except socket.error as e: + print("NO RESPONSE (error: %s)" % str(e)) + if conn: + conn.close() + elif s == ctrl4_tcp: + print("Control channel connected") + conn = None + try: + # Handle control channel input + conn, addr = s.accept() + msg = conn.recv(1024) + if msg: + ctrl_channel(msg) + conn.close() + except s.timeout: + pass + if conn: + conn.close() + + if not running: + break diff --git a/bin/tests/system/digdelv/clean.sh b/bin/tests/system/digdelv/clean.sh new file mode 100644 index 0000000..ed9ad87 --- /dev/null +++ b/bin/tests/system/digdelv/clean.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +set -e + +rm -f ./*/anchor.* +rm -f ./*/named.conf +rm -f ./*/named.memstats +rm -f ./*/named.run +rm -f ./ans*/ans.run +rm -f ./ans*/query.log +rm -f ./delv.out.test* +rm -f ./dig.out.*test* +rm -f ./dig.out.mm.* +rm -f ./dig.out.mn.* +rm -f ./dig.out.nm.* +rm -f ./dig.out.nn.* +rm -f ./host.out.test* +rm -f ./ns*/managed-keys.bind* +rm -f ./ns*/named.lock +rm -f ./ns2/dsset-example. +rm -f ./ns2/example.db ./ns2/K* ./ns2/keyid ./ns2/keydata +rm -f ./nslookup.out.test* +rm -f ./yamlget.out.* +rm -f ./nsupdate.out.test* diff --git a/bin/tests/system/digdelv/ns1/named.conf.in b/bin/tests/system/digdelv/ns1/named.conf.in new file mode 100644 index 0000000..df552bd --- /dev/null +++ b/bin/tests/system/digdelv/ns1/named.conf.in @@ -0,0 +1,30 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +// NS1 + +options { + query-source address 10.53.0.1; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { fd92:7065:b8e:ffff::1; }; + recursion no; + notify yes; + dnssec-validation no; +}; + +zone "." { + type primary; + file "root.db"; +}; diff --git a/bin/tests/system/digdelv/ns1/root.db b/bin/tests/system/digdelv/ns1/root.db new file mode 100644 index 0000000..b43cc40 --- /dev/null +++ b/bin/tests/system/digdelv/ns1/root.db @@ -0,0 +1,26 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; 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 https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +$TTL 300 +. IN SOA gson.nominum.com. a.root.servers.nil. ( + 2000042100 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum + ) +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 +a.root-servers.nil. AAAA fd92:7065:b8e:ffff::1 + +example. NS ns2.example. +ns2.example. A 10.53.0.2 +ns2.example. AAAA fd92:7065:b8e:ffff::2 diff --git a/bin/tests/system/digdelv/ns2/example.db.in b/bin/tests/system/digdelv/ns2/example.db.in new file mode 100644 index 0000000..c711049 --- /dev/null +++ b/bin/tests/system/digdelv/ns2/example.db.in @@ -0,0 +1,51 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; 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 https://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 + NS ns3 +ns2 A 10.53.0.2 +ns2 AAAA fd92:7065:b8e:ffff::2 +ns3 A 10.53.0.3 +ns3 AAAA fd92:7065:b8e:ffff::3 + +a A 10.0.0.1 +a AAAA fd92:7065:b8e:ffff::1 +b A 10.0.0.2 +b AAAA fd92:7065:b8e:ffff::2 +c A 10.0.0.3 +c AAAA fd92:7065:b8e:ffff::3 +d A 10.0.0.0 +d AAAA fd92:7065:b8e:ffff:: + +xn--caf-dma A 10.1.2.3 + +foo TXT "testing" +foo A 10.0.1.0 +foo SSHFP 2 1 123456789abcdef67890123456789abcdef67890 + +; TTL of 3 weeks +weeks 1814400 A 10.53.0.2 +; TTL of 3 days +days 259200 A 10.53.0.2 +; TTL of 3 hours +hours 10800 A 10.53.0.2 +;TTL of 45 minutes +minutes 2700 A 10.53.0.2 +;TTL of 45 seconds +seconds 45 A 10.53.0.2 diff --git a/bin/tests/system/digdelv/ns2/named.conf.in b/bin/tests/system/digdelv/ns2/named.conf.in new file mode 100644 index 0000000..1391b73 --- /dev/null +++ b/bin/tests/system/digdelv/ns2/named.conf.in @@ -0,0 +1,34 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://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; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { fd92:7065:b8e:ffff::2; }; + recursion no; + dnssec-validation no; +}; + +zone "." { + type hint; + file "../../common/root.hint"; +}; + +zone "example" { + type primary; + file "example.db"; +}; diff --git a/bin/tests/system/digdelv/ns2/sign.sh b/bin/tests/system/digdelv/ns2/sign.sh new file mode 100644 index 0000000..c8564b2 --- /dev/null +++ b/bin/tests/system/digdelv/ns2/sign.sh @@ -0,0 +1,29 @@ +#!/bin/sh -e + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# shellcheck source=conf.sh +. ../../conf.sh + +set -e + +ksk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -n zone example.) + +cp example.db.in example.db + +"$SIGNER" -Sz -f example.db -o example example.db.in > /dev/null 2>&1 + +keyfile_to_key_id "$ksk" > keyid +grep -Ev '^;' < "$ksk.key" | cut -f 7- -d ' ' > keydata + +keyfile_to_initial_keys "$ksk" > ../ns3/anchor.dnskey +keyfile_to_initial_ds "$ksk" > ../ns3/anchor.ds diff --git a/bin/tests/system/digdelv/ns3/named.conf.in b/bin/tests/system/digdelv/ns3/named.conf.in new file mode 100644 index 0000000..66bb748 --- /dev/null +++ b/bin/tests/system/digdelv/ns3/named.conf.in @@ -0,0 +1,28 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * 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 https://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.3; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.3; }; + listen-on-v6 { fd92:7065:b8e:ffff::3; }; + recursion yes; + dnssec-validation no; + server-id "ns3"; +}; + +zone "." { + type hint; + file "../../common/root.hint"; +}; diff --git a/bin/tests/system/digdelv/setup.sh b/bin/tests/system/digdelv/setup.sh new file mode 100644 index 0000000..ca63977 --- /dev/null +++ b/bin/tests/system/digdelv/setup.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# shellcheck source=conf.sh +. ../conf.sh + +set -e + +copy_setports ns1/named.conf.in ns1/named.conf +copy_setports ns2/named.conf.in ns2/named.conf +copy_setports ns3/named.conf.in ns3/named.conf + +cd ns2 && $SHELL sign.sh diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh new file mode 100644 index 0000000..dceced6 --- /dev/null +++ b/bin/tests/system/digdelv/tests.sh @@ -0,0 +1,1403 @@ +#!/bin/sh + +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +set -e + +# shellcheck source=conf.sh +. ../conf.sh + +status=0 +n=0 + +sendcmd() { + send "${1}" "$EXTRAPORT1" +} + +dig_with_opts() { + "$DIG" -p "$PORT" "$@" +} + +mdig_with_opts() { + "$MDIG" -p "$PORT" "$@" +} + +# Check if response in file $1 has the correct TTL range. +# The response record must have RRtype $2 and class IN (CLASS1). +# Maximum TTL is given by $3. This works in most cases where TTL is +# the second word on the line. TTL position can be adjusted with +# setting the position $4, but that requires updating this function. +check_ttl_range() { + file=$1 + pos=$4 + + case "$pos" in + "3") + { awk -v rrtype="$2" -v ttl="$3" '($4 == "IN" || $4 == "CLASS1" ) && $5 == rrtype { if ($3 <= ttl) { ok=1 } } END { exit(ok?0:1) }' < $file; result=$?; } || true + ;; + *) + { awk -v rrtype="$2" -v ttl="$3" '($3 == "IN" || $3 == "CLASS1" ) && $4 == rrtype { if ($2 <= ttl) { ok=1 } } END { exit(ok?0:1) }' < $file; result=$?; } || true + ;; + esac + + [ $result -eq 0 ] || echo_i "ttl check failed" + return $result +} + +# using delv insecure mode as not testing dnssec here +delv_with_opts() { + "$DELV" +noroot -p "$PORT" "$@" +} + +KEYID="$(cat ns2/keyid)" +KEYDATA="$(< ns2/keydata sed -e 's/+/[+]/g')" +NOSPLIT="$(< ns2/keydata sed -e 's/+/[+]/g' -e 's/ //g')" + +HAS_PYYAML=0 +if [ -x "$PYTHON" ] ; then + $PYTHON -c "import yaml" 2> /dev/null && HAS_PYYAML=1 +fi + +# +# test whether ans7/ans.pl will be able to send a UPDATE response. +# if it can't, we will log that below. +# +if "$PERL" -e 'use Net::DNS; use Net::DNS::Packet; my $p = new Net::DNS::Packet; $p->header->opcode(5);' > /dev/null 2>&1 +then + checkupdate=1 +else + checkupdate=0 +fi + +if [ -x "$NSLOOKUP" -a $checkupdate -eq 1 ] ; then + + n=$((n+1)) + echo_i "check nslookup handles UPDATE response ($n)" + ret=0 + "$NSLOOKUP" -q=CNAME -timeout=1 "-port=$PORT" foo.bar 10.53.0.7 > nslookup.out.test$n 2>&1 && ret=1 + grep "Opcode mismatch" nslookup.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + +fi + +if [ -x "$HOST" -a $checkupdate -eq 1 ] ; then + + n=$((n+1)) + echo_i "check host handles UPDATE response ($n)" + ret=0 + "$HOST" -W 1 -t CNAME -p $PORT foo.bar 10.53.0.7 > host.out.test$n 2>&1 && ret=1 + grep "Opcode mismatch" host.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + +fi + +if [ -x "$NSUPDATE" -a $checkupdate -eq 1 ] ; then + + n=$((n+1)) + echo_i "check nsupdate handles UPDATE response to QUERY ($n)" + ret=0 + res=0 + $NSUPDATE << EOF > nsupdate.out.test$n 2>&1 || res=$? +server 10.53.0.7 ${PORT} +add x.example.com 300 in a 1.2.3.4 +send +EOF + test $res -eq 1 || ret=1 + grep "invalid OPCODE in response to SOA query" nsupdate.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + +fi + +if [ -x "$DIG" ] ; then + + if [ $checkupdate -eq 1 ] ; then + + n=$((n+1)) + echo_i "check dig handles UPDATE response ($n)" + ret=0 + dig_with_opts @10.53.0.7 +tries=1 +timeout=1 cname foo.bar > dig.out.test$n 2>&1 && ret=1 + grep "Opcode mismatch" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else + echo_i "Skipped UPDATE handling test" + fi + + n=$((n+1)) + echo_i "checking dig short form works ($n)" + ret=0 + dig_with_opts @10.53.0.3 +short a a.example > dig.out.test$n || ret=1 + test "$(wc -l < dig.out.test$n)" -eq 1 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig split width works ($n)" + ret=0 + dig_with_opts @10.53.0.3 +split=4 -t sshfp foo.example > dig.out.test$n || ret=1 + grep " 9ABC DEF6 7890 " < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SSHFP" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +unknownformat works ($n)" + ret=0 + dig_with_opts @10.53.0.3 +unknownformat a a.example > dig.out.test$n || ret=1 + grep "CLASS1[ ][ ]*TYPE1[ ][ ]*\\\\# 4 0A000001" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "TYPE1" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig with reverse lookup works ($n)" + ret=0 + dig_with_opts @10.53.0.3 -x 127.0.0.1 > dig.out.test$n 2>&1 || ret=1 + # doesn't matter if has answer + grep -i "127\\.in-addr\\.arpa\\." < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SOA" 86400 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig over TCP works ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 a a.example > dig.out.test$n || ret=1 + grep "10\\.0\\.0\\.1$" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +multi +norrcomments works for DNSKEY (when default is rrcomments)($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t DNSKEY example > dig.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" dig.out.test$n > /dev/null && ret=1 + check_ttl_range dig.out.test$n "DNSKEY" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +multi +norrcomments works for SOA (when default is rrcomments)($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t SOA example > dig.out.test$n || ret=1 + grep "; serial" dig.out.test$n > /dev/null && ret=1 + check_ttl_range dig.out.test$n "SOA" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +rrcomments works for DNSKEY($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +rrcomments DNSKEY example > dig.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "DNSKEY" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +short +rrcomments works for DNSKEY ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example > dig.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +short +nosplit works($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +short +nosplit DNSKEY example > dig.out.test$n || ret=1 + grep "$NOSPLIT" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +short +rrcomments works($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example > dig.out.test$n || ret=1 + grep -q "$KEYDATA ; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID\$" < dig.out.test$n || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig multi flag is local($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +nomulti example +nomulti > dig.out.nn.$n || ret=1 + dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +multi example +nomulti > dig.out.mn.$n || ret=1 + dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +nomulti example +multi > dig.out.nm.$n || ret=1 + dig_with_opts +tcp @10.53.0.3 -t DNSKEY example +multi example +multi > dig.out.mm.$n || ret=1 + lcnn=$(wc -l < dig.out.nn.$n) + lcmn=$(wc -l < dig.out.mn.$n) + lcnm=$(wc -l < dig.out.nm.$n) + lcmm=$(wc -l < dig.out.mm.$n) + test "$lcmm" -ge "$lcnm" || ret=1 + test "$lcmm" -ge "$lcmn" || ret=1 + test "$lcnm" -ge "$lcnn" || ret=1 + test "$lcmn" -ge "$lcnn" || ret=1 + check_ttl_range dig.out.nn.$n "DNSKEY" 300 || ret=1 + check_ttl_range dig.out.mn.$n "DNSKEY" 300 || ret=1 + check_ttl_range dig.out.nm.$n "DNSKEY" 300 || ret=1 + check_ttl_range dig.out.mm.$n "DNSKEY" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +noheader-only works ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +noheader-only A example > dig.out.test$n || ret=1 + grep "Got answer:" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SOA" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +short +rrcomments works($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example > dig.out.test$n || ret=1 + grep -q "$KEYDATA ; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID\$" < dig.out.test$n || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +header-only works ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +header-only example > dig.out.test$n || ret=1 + grep "^;; flags: qr rd; QUERY: 0, ANSWER: 0," < dig.out.test$n > /dev/null || ret=1 + grep "^;; QUESTION SECTION:" < dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +raflag works ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +raflag +qr example > dig.out.test$n || ret=1 + grep "^;; flags: rd ra ad; QUERY: 1, ANSWER: 0," < dig.out.test$n > /dev/null || ret=1 + grep "^;; flags: qr rd ra; QUERY: 1, ANSWER: 0," < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SOA" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +tcflag works ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +tcflag +qr example > dig.out.test$n || ret=1 + grep "^;; flags: tc rd ad; QUERY: 1, ANSWER: 0" < dig.out.test$n > /dev/null || ret=1 + grep "^;; flags: qr rd ra; QUERY: 1, ANSWER: 0," < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SOA" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +header-only works (with class and type set) ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +header-only -c IN -t A example > dig.out.test$n || ret=1 + grep "^;; flags: qr rd; QUERY: 0, ANSWER: 0," < dig.out.test$n > /dev/null || ret=1 + grep "^;; QUESTION SECTION:" < dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +zflag works, and that BIND properly ignores it ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.3 +zflag +qr A example > dig.out.test$n || ret=1 + sed -n '/Sending:/,/Got answer:/p' dig.out.test$n | grep "^;; flags: rd ad; MBZ: 0x4;" > /dev/null || ret=1 + sed -n '/Got answer:/,/AUTHORITY SECTION:/p' dig.out.test$n | grep "^;; flags: qr rd ra; QUERY: 1" > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SOA" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +qr +ednsopt=08 does not cause an INSIST failure ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=08 +qr a a.example > dig.out.test$n || ret=1 + grep "INSIST" < dig.out.test$n > /dev/null && ret=1 + grep "FORMERR" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +ttlunits works ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +ttlunits A weeks.example > dig.out.test$n || ret=1 + grep "^weeks.example. 3w" < dig.out.test$n > /dev/null || ret=1 + dig_with_opts +tcp @10.53.0.2 +ttlunits A days.example > dig.out.test$n || ret=1 + grep "^days.example. 3d" < dig.out.test$n > /dev/null || ret=1 + dig_with_opts +tcp @10.53.0.2 +ttlunits A hours.example > dig.out.test$n || ret=1 + grep "^hours.example. 3h" < dig.out.test$n > /dev/null || ret=1 + dig_with_opts +tcp @10.53.0.2 +ttlunits A minutes.example > dig.out.test$n || ret=1 + grep "^minutes.example. 45m" < dig.out.test$n > /dev/null || ret=1 + dig_with_opts +tcp @10.53.0.2 +ttlunits A seconds.example > dig.out.test$n || ret=1 + grep "^seconds.example. 45s" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig respects precedence of options with +ttlunits ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +ttlunits +nottlid A weeks.example > dig.out.test$n || ret=1 + grep "^weeks.example. IN" < dig.out.test$n > /dev/null || ret=1 + dig_with_opts +tcp @10.53.0.2 +nottlid +ttlunits A weeks.example > dig.out.test$n || ret=1 + grep "^weeks.example. 3w" < dig.out.test$n > /dev/null || ret=1 + dig_with_opts +tcp @10.53.0.2 +nottlid +nottlunits A weeks.example > dig.out.test$n || ret=1 + grep "^weeks.example. 1814400" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig preserves origin on TCP retries ($n)" + ret=0 + # Ask ans4 to still accept TCP connections, but not respond to queries + echo "//" | sendcmd 10.53.0.4 + dig_with_opts -d +tcp @10.53.0.4 +retry=1 +time=1 +domain=bar foo > dig.out.test$n 2>&1 && ret=1 + test "$(grep -c "trying origin bar" dig.out.test$n)" -eq 2 || ret=1 + grep "using root origin" < dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig -6 -4 ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 -4 -6 A a.example > dig.out.test$n 2>&1 && ret=1 + grep "only one of -4 and -6 allowed" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig @IPv6addr -4 A a.example ($n)" + if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null + then + ret=0 + dig_with_opts +tcp @fd92:7065:b8e:ffff::2 -4 A a.example > dig.out.test$n 2>&1 && ret=1 + grep "address family not supported" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else + echo_i "IPv6 unavailable; skipping" + fi + + n=$((n+1)) + echo_i "checking dig +tcp @IPv4addr -6 A a.example ($n)" + if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null + then + ret=0 + dig_with_opts +tcp @10.53.0.2 -6 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "SERVER: ::ffff:10.53.0.2#$PORT" < dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else + echo_i "IPv6 unavailable; skipping" + fi + n=$((n+1)) + + echo_i "checking dig +notcp @IPv4addr -6 A a.example ($n)" + if testsock6 fd92:7065:b8e:ffff::2 2>/dev/null + then + ret=0 + dig_with_opts +notcp @10.53.0.2 -6 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "SERVER: ::ffff:10.53.0.2#$PORT" < dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else + echo_i "IPv6 unavailable; skipping" + fi + + n=$((n+1)) + echo_i "checking dig +subnet ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +subnet=127.0.0.1 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "CLIENT-SUBNET: 127.0.0.1/32/0" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +subnet +subnet ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +subnet=127.0.0.0 +subnet=127.0.0.1 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "CLIENT-SUBNET: 127.0.0.1/32/0" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +subnet with various prefix lengths ($n)" + ret=0 + for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24; do + dig_with_opts +tcp @10.53.0.2 +subnet=255.255.255.255/$i A a.example > dig.out.$i.test$n 2>&1 || ret=1 + case $i in + 1|9|17) octet=128 ;; + 2|10|18) octet=192 ;; + 3|11|19) octet=224 ;; + 4|12|20) octet=240 ;; + 5|13|21) octet=248 ;; + 6|14|22) octet=252 ;; + 7|15|23) octet=254 ;; + 8|16|24) octet=255 ;; + esac + case $i in + 1|2|3|4|5|6|7|8) addr="${octet}.0.0.0";; + 9|10|11|12|13|14|15|16) addr="255.${octet}.0.0";; + 17|18|19|20|21|22|23|24) addr="255.255.${octet}.0" ;; + esac + grep "FORMERR" < dig.out.$i.test$n > /dev/null && ret=1 + grep "CLIENT-SUBNET: $addr/$i/0" < dig.out.$i.test$n > /dev/null || ret=1 + check_ttl_range dig.out.$i.test$n "A" 300 || ret=1 + done + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +subnet=0/0 ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +subnet=0/0 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "status: NOERROR" < dig.out.test$n > /dev/null || ret=1 + grep "CLIENT-SUBNET: 0.0.0.0/0/0" < dig.out.test$n > /dev/null || ret=1 + grep "10.0.0.1" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +subnet=0 ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +subnet=0 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "status: NOERROR" < dig.out.test$n > /dev/null || ret=1 + grep "CLIENT-SUBNET: 0.0.0.0/0/0" < dig.out.test$n > /dev/null || ret=1 + grep "10.0.0.1" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +subnet=::/0 ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +subnet=::/0 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "status: NOERROR" < dig.out.test$n > /dev/null || ret=1 + grep "CLIENT-SUBNET: ::/0/0" < dig.out.test$n > /dev/null || ret=1 + grep "10.0.0.1" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +ednsopt=8:00000000 (family=0, source=0, scope=0) ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.2 +ednsopt=8:00000000 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "status: NOERROR" < dig.out.test$n > /dev/null || ret=1 + grep "CLIENT-SUBNET: 0/0/0" < dig.out.test$n > /dev/null || ret=1 + grep "10.0.0.1" < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +ednsopt=8:00030000 (family=3, source=0, scope=0) ($n)" + ret=0 + dig_with_opts +qr +tcp @10.53.0.2 +ednsopt=8:00030000 A a.example > dig.out.test$n 2>&1 || ret=1 + grep "status: FORMERR" < dig.out.test$n > /dev/null || ret=1 + grep "CLIENT-SUBNET: 00 03 00 00" < dig.out.test$n > /dev/null || ret=1 + test "$(grep -c "CLIENT-SUBNET: 00 03 00 00" dig.out.test$n)" -eq 1 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +subnet with prefix lengths between byte boundaries ($n)" + ret=0 + for p in 9 10 11 12 13 14 15; do + dig_with_opts +tcp @10.53.0.2 +subnet=10.53/$p A a.example > dig.out.test.$p.$n 2>&1 || ret=1 + grep "FORMERR" < dig.out.test.$p.$n > /dev/null && ret=1 + grep "CLIENT-SUBNET.*/$p/0" < dig.out.test.$p.$n > /dev/null || ret=1 + check_ttl_range dig.out.test.$p.$n "A" 300 || ret=1 + done + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +sp works as an abbreviated form of split ($n)" + ret=0 + dig_with_opts @10.53.0.3 +sp=4 -t sshfp foo.example > dig.out.test$n || ret=1 + grep " 9ABC DEF6 7890 " < dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "SSHFP" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig -c works ($n)" + ret=0 + dig_with_opts @10.53.0.3 -c CHAOS -t txt version.bind > dig.out.test$n || ret=1 + grep "version.bind. 0 CH TXT" < dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +ednsopt with option number ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=3 a.example > dig.out.test$n 2>&1 || ret=1 + grep 'NSID: .* ("ns3")' dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking dig +ednsopt with option name ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=nsid a.example > dig.out.test$n 2>&1 || ret=1 + grep 'NSID: .* ("ns3")' dig.out.test$n > /dev/null || ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking ednsopt LLQ prints as expected ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=llq:0001000200001234567812345678fefefefe +qr a.example > dig.out.test$n 2>&1 || ret=1 + pat='LLQ: Version: 1, Opcode: 2, Error: 0, Identifier: 1311768465173141112, Lifetime: 4278124286$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking that dig warns about .local queries ($n)" + ret=0 + dig_with_opts @10.53.0.3 local soa > dig.out.test$n 2>&1 || ret=1 + grep ";; WARNING: .local is reserved for Multicast DNS" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig processes +ednsopt=key-tag and FORMERR is returned ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=key-tag a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; KEY-TAG: *$" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig processes +ednsopt=key-tag:<value-list> ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=key-tag:00010002 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; KEY-TAG: 1, 2$" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null && ret=1 + check_ttl_range dig.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig processes +ednsopt=key-tag:<malformed-value-list> and FORMERR is returned ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=key-tag:0001000201 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; KEY-TAG: 00 01 00 02 01" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig processes +ednsopt=client-tag:value ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=client-tag:0001 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; CLIENT-TAG: 1$" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that FORMERR is returned for a too short client-tag ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=client-tag:01 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; CLIENT-TAG" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that FORMERR is returned for a too long client-tag ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=client-tag:000001 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; CLIENT-TAG" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig processes +ednsopt=server-tag:value ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=server-tag:0001 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; SERVER-TAG: 1$" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that FORMERR is returned for a too short server-tag ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=server-tag:01 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; SERVER-TAG" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that FORMERR is returned for a too long server-tag ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=server-tag:000001 a.example +qr > dig.out.test$n 2>&1 || ret=1 + grep "; SERVER-TAG" dig.out.test$n > /dev/null || ret=1 + grep "status: FORMERR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that Extended DNS Error 0 is printed correctly ($n)" + # First defined EDE code, additional text "foo". + dig_with_opts @10.53.0.3 +ednsopt=ede:0000666f6f a.example +qr > dig.out.test$n 2>&1 || ret=1 + pat='^; EDE: 0 (Other): (foo)$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that Extended DNS Error 24 is printed correctly ($n)" + # Last defined EDE code, no additional text. + dig_with_opts @10.53.0.3 +ednsopt=ede:0018 a.example +qr > dig.out.test$n 2>&1 || ret=1 + pat='^; EDE: 24 (Invalid Data)$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that Extended DNS Error 25 is printed correctly ($n)" + # First undefined EDE code, additional text "foo". + dig_with_opts @10.53.0.3 +ednsopt=ede:0019666f6f a.example +qr > dig.out.test$n 2>&1 || ret=1 + pat='^; EDE: 25: (foo)$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that invalid Extended DNS Error (length 0) is printed ($n)" + # EDE payload is too short + dig_with_opts @10.53.0.3 +ednsopt=ede a.example +qr > dig.out.test$n 2>&1 || ret=1 + pat='^; EDE:$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that invalid Extended DNS Error (length 1) is printed ($n)" + # EDE payload is too short + dig_with_opts @10.53.0.3 +ednsopt=ede:00 a.example +qr > dig.out.test$n 2>&1 || ret=1 + pat='^; EDE: 00 (".")$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + if [ $HAS_PYYAML -ne 0 ] ; then + n=$((n+1)) + echo_i "check that +yaml Extended DNS Error 0 is printed correctly ($n)" + # First defined EDE code, additional text "foo". + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0000666f6f a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "0 (Other)" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "foo" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that +yaml Extended DNS Error 24 is printed correctly ($n)" + # Last defined EDE code, no additional text. + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0018 a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "24 (Invalid Data)" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT > yamlget.out.test$n 2>&1 && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that +yaml Extended DNS Error 25 is printed correctly ($n)" + # First undefined EDE code, additional text "foo". + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:0019666f6f a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE INFO-CODE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "25" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE EXTRA-TEXT > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "foo" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that invalid Extended DNS Error (length 0) is printed ($n)" + # EDE payload is too short + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "None" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that invalid +yaml Extended DNS Error (length 1) is printed ($n)" + # EDE payload is too short + dig_with_opts @10.53.0.3 +yaml +ednsopt=ede:00 a.example +qr > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS EDE > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = '00 (".")' ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + fi + + n=$((n+1)) + echo_i "check that dig handles malformed option '+ednsopt=:' gracefully ($n)" + ret=0 + dig_with_opts @10.53.0.3 +ednsopt=: a.example > dig.out.test$n 2>&1 && ret=1 + grep "ednsopt no code point specified" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig gracefully handles bad escape in domain name ($n)" + ret=0 + digstatus=0 + dig_with_opts @10.53.0.3 '\0.' > dig.out.test$n 2>&1 || digstatus=$? + echo digstatus=$digstatus >> dig.out.test$n + test $digstatus -eq 10 || ret=1 + grep REQUIRE dig.out.test$n > /dev/null && ret=1 + grep "is not a legal name (bad escape)" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig -q -m works ($n)" + ret=0 + dig_with_opts @10.53.0.3 -q -m > dig.out.test$n 2>&1 + pat='^;-m\..*IN.*A$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + grep "Dump of all outstanding memory allocations" dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking exit code for a retry upon TCP EOF (immediate -> immediate) ($n)" + ret=0 + echo "no_response no_response" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=2 > dig.out.test$n 2>&1 && ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> partial AXFR) ($n)" + ret=0 + echo "partial_axfr partial_axfr" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=2 > dig.out.test$n 2>&1 && ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking exit code for a retry upon TCP EOF (immediate -> partial AXFR) ($n)" + ret=0 + echo "no_response partial_axfr" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=2 > dig.out.test$n 2>&1 && ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> immediate) ($n)" + ret=0 + echo "partial_axfr no_response" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=2 > dig.out.test$n 2>&1 && ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking exit code for a retry upon TCP EOF (immediate -> complete AXFR) ($n)" + ret=0 + echo "no_response complete_axfr" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=2 > dig.out.test$n 2>&1 || ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> complete AXFR) ($n)" + ret=0 + echo "partial_axfr complete_axfr" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=2 > dig.out.test$n 2>&1 || ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking +tries=1 won't retry twice upon TCP EOF ($n)" + ret=0 + echo "no_response no_response" | sendcmd 10.53.0.5 + dig_with_opts @10.53.0.5 example AXFR +tries=1 > dig.out.test$n 2>&1 && ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking +retry=0 won't retry twice upon TCP EOF ($n)" + ret=0 + dig_with_opts @10.53.0.5 example AXFR +retry=0 > dig.out.test$n 2>&1 && ret=1 + # Sanity check: ensure ans5 behaves as expected. + [ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig +expandaaaa works ($n)" + ret=0 + dig_with_opts @10.53.0.3 +expandaaaa AAAA ns2.example > dig.out.test$n 2>&1 || ret=1 + grep "ns2.example.*fd92:7065:0b8e:ffff:0000:0000:0000:0002" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig +noexpandaaaa works ($n)" + ret=0 + dig_with_opts @10.53.0.3 +noexpandaaaa AAAA ns2.example > dig.out.test$n 2>&1 || ret=1 + grep "ns2.example.*fd92:7065:b8e:ffff::2" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig default for +[no]expandaaa (+noexpandaaaa) works ($n)" + ret=0 + dig_with_opts @10.53.0.3 AAAA ns2.example > dig.out.test$n 2>&1 || ret=1 + grep "ns2.example.*fd92:7065:b8e:ffff::2" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + + echo_i "check that dig +short +expandaaaa works ($n)" + ret=0 + dig_with_opts @10.53.0.3 +short +expandaaaa AAAA ns2.example > dig.out.test$n 2>&1 || ret=1 + pat='^fd92:7065:0b8e:ffff:0000:0000:0000:0002$' + grep "$pat" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + if [ $HAS_PYYAML -ne 0 ] ; then + n=$((n+1)) + echo_i "check dig +yaml output ($n)" + ret=0 + dig_with_opts +qr +yaml @10.53.0.3 any ns2.example > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message query_message_data status > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "NOERROR" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 1 message response_message_data status > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "NOERROR" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 1 message response_message_data QUESTION_SECTION 0 > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "ns2.example. IN ANY" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check dig +yaml output of an IPv6 address ending in zeroes ($n)" + ret=0 + dig_with_opts +qr +yaml @10.53.0.3 aaaa d.example > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 1 message response_message_data ANSWER_SECTION 0 > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "d.example. 300 IN AAAA fd92:7065:b8e:ffff::0" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + fi + + n=$((n+1)) + echo_i "check that dig +bufsize=0 just sets the buffer size to 0 ($n)" + ret=0 + dig_with_opts @10.53.0.3 a.example +bufsize=0 +qr > dig.out.test$n 2>&1 || ret=1 + grep "EDNS:" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig +bufsize restores default bufsize ($n)" + ret=0 + dig_with_opts @10.53.0.3 a.example +bufsize=0 +bufsize +qr > dig.out.test$n 2>&1 || ret=1 + lines=$(grep "EDNS:.* udp:" dig.out.test$n | wc -l) + lines1232=$(grep "EDNS:.* udp: 1232" dig.out.test$n | wc -l) + test $lines -eq 2 || ret=1 + test $lines1232 -eq 2 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig without -u displays 'Query time' in millseconds ($n)" + ret=0 + dig_with_opts @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep ';; Query time: [0-9][0-9]* msec' dig.out.test$n >/dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig -u displays 'Query time' in microseconds ($n)" + ret=0 + dig_with_opts -u @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep ';; Query time: [0-9][0-9]* usec' dig.out.test$n >/dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig +yaml without -u displays timestamps in milliseconds ($n)" + ret=0 + dig_with_opts +yaml @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep 'query_time: !!timestamp ....-..-..T..:..:..\....Z' dig.out.test$n >/dev/null || ret=1 + grep 'response_time: !!timestamp ....-..-..T..:..:..\....Z' dig.out.test$n >/dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig -u +yaml displays timestamps in microseconds ($n)" + ret=0 + dig_with_opts -u +yaml @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep 'query_time: !!timestamp ....-..-..T..:..:..\.......Z' dig.out.test$n >/dev/null || ret=1 + grep 'response_time: !!timestamp ....-..-..T..:..:..\.......Z' dig.out.test$n >/dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + # See [GL #3020] for more information + n=$((n+1)) + echo_i "check that dig handles UDP timeout followed by a SERVFAIL correctly ($n)" + # Ask ans8 to be in "unstable" mode (switching between "silent" and "servfail" modes) + echo "unstable" | sendcmd 10.53.0.8 + ret=0 + dig_with_opts +timeout=1 +nofail @10.53.0.8 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig handles TCP timeout followed by a SERVFAIL correctly ($n)" + # Ask ans8 to be in "unstable" mode (switching between "silent" and "servfail" modes) + echo "unstable" | sendcmd 10.53.0.8 + ret=0 + dig_with_opts +timeout=1 +nofail +tcp @10.53.0.8 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "status: SERVFAIL" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig tries the next server after a UDP socket network unreachable error ($n)" + ret=0 + dig_with_opts @192.0.2.128 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + test $(grep -F -e "connection refused" -e "timed out" -e "network unreachable" -e "host unreachable" dig.out.test$n | wc -l) -eq 3 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig tries the next server after a TCP socket network unreachable error ($n)" + ret=0 + dig_with_opts +tcp @192.0.2.128 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + test $(grep -F -e "connection refused" -e "timed out" -e "network unreachable" -e "host unreachable" dig.out.test$n | wc -l) -eq 3 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig tries the next server after a UDP socket read error ($n)" + ret=0 + dig_with_opts @10.53.0.99 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig tries the next server after a TCP socket read error ($n)" + # Ask ans8 to be in "close" mode, which closes the connection after accepting it + echo "close" | sendcmd 10.53.0.8 + ret=0 + dig_with_opts +tcp @10.53.0.8 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + # Note that we combine TCP socket "connection error" and "timeout" cases in + # one, because it is not trivial to simulate the timeout case in a system test + # in Linux without a firewall, but the code which handles error cases during + # the connection establishment time does not differentiate between timeout and + # other types of errors (unlike during reading), so this one check should be + # sufficient for both cases. + n=$((n+1)) + echo_i "check that dig tries the next server after a TCP socket connection error/timeout ($n)" + ret=0 + dig_with_opts +tcp @10.53.0.99 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + test $(grep -F -e "connection refused" -e "timed out" -e "network unreachable" dig.out.test$n | wc -l) -eq 3 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig tries the next server after UDP socket read timeouts ($n)" + # Ask ans8 to be in "silent" mode + echo "silent" | sendcmd 10.53.0.8 + ret=0 + dig_with_opts +timeout=1 @10.53.0.8 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that dig tries the next server after TCP socket read timeouts ($n)" + # Ask ans8 to be in "silent" mode + echo "silent" | sendcmd 10.53.0.8 + ret=0 + dig_with_opts +timeout=1 +tcp @10.53.0.8 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "status: NOERROR" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + # See [GL #3248] for more information + n=$((n+1)) + echo_i "check that dig correctly refuses to use a server with a IPv4 mapped IPv6 address after failing with a regular IP address ($n)" + ret=0 + dig_with_opts @10.53.0.8 @::ffff:10.53.0.8 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F ";; Skipping mapped address" dig.out.test$n > /dev/null || ret=1 + grep -F ";; No acceptable nameservers" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + # See [GL #3244] for more information + n=$((n+1)) + echo_i "check that dig handles printing query information with +qr and +y when multiple queries are involved (including a failed query) ($n)" + ret=0 + dig_with_opts +timeout=1 +qr +y @127.0.0.1 @10.53.0.3 a.example > dig.out.test$n 2>&1 || ret=1 + grep -F "IN A 10.0.0.1" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) +else + echo_i "$DIG is needed, so skipping these dig tests" +fi + +if [ -x "$MDIG" ] ; then + n=$((n+1)) + echo_i "check that mdig handles malformed option '+ednsopt=:' gracefully ($n)" + ret=0 + mdig_with_opts @10.53.0.3 +ednsopt=: a.example > dig.out.test$n 2>&1 && ret=1 + grep "ednsopt no code point specified" dig.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking mdig +multi +norrcomments works for DNSKEY (when default is rrcomments)($n)" + ret=0 + mdig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t DNSKEY example > dig.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" dig.out.test$n && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking mdig +multi +norrcomments works for SOA (when default is rrcomments)($n)" + ret=0 + mdig_with_opts +tcp @10.53.0.3 +multi +norrcomments -t SOA example > dig.out.test$n || ret=1 + grep "; serial" < dig.out.test$n > /dev/null && ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + if [ $HAS_PYYAML -ne 0 ] ; then + n=$((n+1)) + echo_i "check mdig +yaml output ($n)" + ret=0 + mdig_with_opts +yaml @10.53.0.3 -t any ns2.example > dig.out.test$n 2>&1 || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message response_message_data status > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "NOERROR" ] || ret=1 + $PYTHON yamlget.py dig.out.test$n 0 message response_message_data QUESTION_SECTION 0 > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "ns2.example. IN ANY" ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + fi +else + echo_i "$MDIG is needed, so skipping these mdig tests" +fi + +if [ -x "$DELV" ] ; then + n=$((n+1)) + echo_i "checking delv short form works ($n)" + ret=0 + delv_with_opts @10.53.0.3 +short a a.example > delv.out.test$n || ret=1 + test "$(wc -l < delv.out.test$n)" -eq 1 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv split width works ($n)" + ret=0 + delv_with_opts @10.53.0.3 +split=4 -t sshfp foo.example > delv.out.test$n || ret=1 + grep " 9ABC DEF6 7890 " < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "SSHFP" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +unknownformat works ($n)" + ret=0 + delv_with_opts @10.53.0.3 +unknownformat a a.example > delv.out.test$n || ret=1 + grep "CLASS1[ ][ ]*TYPE1[ ][ ]*\\\\# 4 0A000001" < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "TYPE1" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv -4 -6 ($n)" + ret=0 + delv_with_opts @10.53.0.3 -4 -6 A a.example > delv.out.test$n 2>&1 && ret=1 + grep "only one of -4 and -6 allowed" < delv.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv with IPv6 on IPv4 does not work ($n)" + if testsock6 fd92:7065:b8e:ffff::3 2>/dev/null + then + ret=0 + # following should fail because @IPv4 overrides earlier @IPv6 above + # and -6 forces IPv6 so this should fail, with a message + # "Use of IPv4 disabled by -6" + delv_with_opts @fd92:7065:b8e:ffff::3 @10.53.0.3 -6 -t txt foo.example > delv.out.test$n 2>&1 && ret=1 + # it should have no results but error output + grep "testing" < delv.out.test$n > /dev/null && ret=1 + grep "Use of IPv4 disabled by -6" delv.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else + echo_i "IPv6 unavailable; skipping" + fi + + n=$((n+1)) + echo_i "checking delv with IPv4 on IPv6 does not work ($n)" + if testsock6 fd92:7065:b8e:ffff::3 2>/dev/null + then + ret=0 + # following should fail because @IPv6 overrides earlier @IPv4 above + # and -4 forces IPv4 so this should fail, with a message + # "Use of IPv6 disabled by -4" + delv_with_opts @10.53.0.3 @fd92:7065:b8e:ffff::3 -4 -t txt foo.example > delv.out.test$n 2>&1 && ret=1 + # it should have no results but error output + grep "testing" delv.out.test$n > /dev/null && ret=1 + grep "Use of IPv6 disabled by -4" delv.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + else + echo_i "IPv6 unavailable; skipping" + fi + + n=$((n+1)) + echo_i "checking delv with reverse lookup works ($n)" + ret=0 + delv_with_opts @10.53.0.3 -x 127.0.0.1 > delv.out.test$n 2>&1 || ret=1 + # doesn't matter if has answer + grep -i "127\\.in-addr\\.arpa\\." < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n '\\-ANY' 10800 3 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv over TCP works ($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 a a.example > delv.out.test$n || ret=1 + grep "10\\.0\\.0\\.1$" < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +multi +norrcomments works for DNSKEY (when default is rrcomments)($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +multi +norrcomments DNSKEY example > delv.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < delv.out.test$n > /dev/null && ret=1 + check_ttl_range delv.out.test$n "DNSKEY" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +multi +norrcomments works for SOA (when default is rrcomments)($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +multi +norrcomments SOA example > delv.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < delv.out.test$n > /dev/null && ret=1 + check_ttl_range delv.out.test$n "SOA" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +rrcomments works for DNSKEY($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +rrcomments DNSKEY example > delv.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "DNSKEY" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +short +rrcomments works for DNSKEY ($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example > delv.out.test$n || ret=1 + grep "; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < delv.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +short +rrcomments works ($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +short +rrcomments DNSKEY example > delv.out.test$n || ret=1 + grep -q "$KEYDATA ; ZSK; alg = $DEFAULT_ALGORITHM ; key id = $KEYID" < delv.out.test$n || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +short +nosplit works ($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +short +nosplit DNSKEY example > delv.out.test$n || ret=1 + grep -q "$NOSPLIT" < delv.out.test$n || ret=1 + test "$(wc -l < delv.out.test$n)" -eq 1 || ret=1 + test "$(awk '{print NF}' < delv.out.test$n)" -eq 14 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +short +nosplit +norrcomments works ($n)" + ret=0 + delv_with_opts +tcp @10.53.0.3 +short +nosplit +norrcomments DNSKEY example > delv.out.test$n || ret=1 + grep -q "$NOSPLIT\$" < delv.out.test$n || ret=1 + test "$(wc -l < delv.out.test$n)" -eq 1 || ret=1 + test "$(awk '{print NF}' < delv.out.test$n)" -eq 4 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +sp works as an abbriviated form of split ($n)" + ret=0 + delv_with_opts @10.53.0.3 +sp=4 -t sshfp foo.example > delv.out.test$n || ret=1 + grep " 9ABC DEF6 7890 " < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "SSHFP" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv +sh works as an abbriviated form of short ($n)" + ret=0 + delv_with_opts @10.53.0.3 +sh a a.example > delv.out.test$n || ret=1 + test "$(wc -l < delv.out.test$n)" -eq 1 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv -c IN works ($n)" + ret=0 + delv_with_opts @10.53.0.3 -c IN -t a a.example > delv.out.test$n || ret=1 + grep "a.example." < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv -c CH is ignored, and treated like IN ($n)" + ret=0 + delv_with_opts @10.53.0.3 -c CH -t a a.example > delv.out.test$n || ret=1 + grep "a.example." < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "checking delv H is ignored, and treated like IN ($n)" + ret=0 + delv_with_opts @10.53.0.3 -c CH -t a a.example > delv.out.test$n || ret=1 + grep "a.example." < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n "A" 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that delv -q -m works ($n)" + ret=0 + delv_with_opts @10.53.0.3 -q -m > delv.out.test$n 2>&1 || ret=1 + grep '^; -m\..*[0-9]*.*IN.*ANY.*;' delv.out.test$n > /dev/null || ret=1 + grep "^add " delv.out.test$n > /dev/null && ret=1 + grep "^del " delv.out.test$n > /dev/null && ret=1 + check_ttl_range delv.out.test$n '\\-ANY' 300 3 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that delv -t ANY works ($n)" + ret=0 + delv_with_opts @10.53.0.3 -t ANY example > delv.out.test$n 2>&1 || ret=1 + grep "^example." < delv.out.test$n > /dev/null || ret=1 + check_ttl_range delv.out.test$n NS 300 || ret=1 + check_ttl_range delv.out.test$n SOA 300 || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that delv loads key-style trust anchors ($n)" + ret=0 + delv_with_opts -a ns3/anchor.dnskey +root=example @10.53.0.3 -t DNSKEY example > delv.out.test$n 2>&1 || ret=1 + grep "fully validated" delv.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + n=$((n+1)) + echo_i "check that delv loads DS-style trust anchors ($n)" + ret=0 + delv_with_opts -a ns3/anchor.ds +root=example @10.53.0.3 -t DNSKEY example > delv.out.test$n 2>&1 || ret=1 + grep "fully validated" delv.out.test$n > /dev/null || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + + if [ $HAS_PYYAML -ne 0 ] ; then + n=$((n+1)) + echo_i "check delv +yaml output ($n)" + ret=0 + delv_with_opts +yaml @10.53.0.3 any ns2.example > delv.out.test$n || ret=1 + $PYTHON yamlget.py delv.out.test$n status > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "success" ] || ret=1 + $PYTHON yamlget.py delv.out.test$n query_name > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + [ "$value" = "ns2.example" ] || ret=1 + $PYTHON yamlget.py delv.out.test$n records 0 answer_not_validated 0 > yamlget.out.test$n 2>&1 || ret=1 + read -r value < yamlget.out.test$n + count=$(echo $value | wc -w ) + [ ${count:-0} -eq 5 ] || ret=1 + if [ $ret -ne 0 ]; then echo_i "failed"; fi + status=$((status+ret)) + fi +else + echo_i "$DELV is needed, so skipping these delv tests" +fi + +echo_i "exit status: $status" +[ $status -eq 0 ] || exit 1 diff --git a/bin/tests/system/digdelv/tests_sh_digdelv.py b/bin/tests/system/digdelv/tests_sh_digdelv.py new file mode 100644 index 0000000..2973c26 --- /dev/null +++ b/bin/tests/system/digdelv/tests_sh_digdelv.py @@ -0,0 +1,14 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + + +def test_digdelv(run_tests_sh): + run_tests_sh() diff --git a/bin/tests/system/digdelv/yamlget.py b/bin/tests/system/digdelv/yamlget.py new file mode 100644 index 0000000..afa582d --- /dev/null +++ b/bin/tests/system/digdelv/yamlget.py @@ -0,0 +1,35 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# 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 https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import sys + +try: + import yaml +# pylint: disable=bare-except +except: + print("No python yaml module, skipping") + sys.exit(1) + +with open(sys.argv[1], "r", encoding="utf-8") as f: + for item in yaml.safe_load_all(f): + for key in sys.argv[2:]: + try: + key = int(key) + except ValueError: + pass + + try: + item = item[key] + except KeyError: + print('Key "' + key + '" not found.') + sys.exit(1) + + print(item) |