+4823. [test] Refactor reclimit system test to improve its
+ reliability and speed. [RT #46632]
+
4822. [bug] Use resign_sooner in dns_db_setsigningtime. [RT #46473]
4821. [bug] When resigning ensure that the SOA's expire time is
system test for recursion limits
ns1 -- root server
-ans2 -- delegate to ns1.(n+1).example.com for all n, up to
- the value specified in ans.limit (or forever if limit is 0)
+ans2 -- for example.org: delegate to ns1.(n+1).example.org for all n, up to the
+ value specified in ans.limit (or forever if limit is 0)
+ for example.net: delegate every query to 15 more name servers, with
+ "victim" address
ns3 -- resolver under test
-ans4 -- delegates every query to 16 more name servers, with "victim" address
ans7 -- "victim" server
use warnings;
use IO::File;
-use Getopt::Long;
-use Net::DNS::Nameserver;
-use Time::HiRes qw(usleep nanosleep);
+use IO::Socket;
+use Net::DNS;
+
+my $localaddr = "10.53.0.2";
+my $limit = getlimit();
+my $no_more_waiting = 0;
+my @delayed_response;
+my $timeout;
+
+my $udpsock = IO::Socket::INET->new(LocalAddr => "$localaddr",
+ LocalPort => 5300, Proto => "udp", 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: $!";
return 0;
}
-my $localaddr = "10.53.0.2";
-my $localport = 5300;
-my $verbose = 0;
-my $limit = getlimit();
-
+# If $wait == 0 is returned, returned reply will be sent immediately.
+# If $wait == 1 is returned, sending the returned reply might be delayed; see
+# comments inside handle_UDP() for details.
sub reply_handler {
- my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_;
- my ($rcode, @ans, @auth, @add);
+ my ($qname, $qclass, $qtype) = @_;
+ my ($rcode, @ans, @auth, @add, $wait);
print ("request: $qname/$qtype\n");
STDOUT->flush();
+ $wait = 0;
$count += 1;
- # Sleep 100ms to make sure that named sends both A and AAAA queries.
- usleep(100000);
if ($qname eq "count" ) {
if ($qtype eq "TXT") {
$rcode = "NOERROR";
} elsif ($qname =~ /^ns1\.(\d+)\.example\.org$/) {
my $next = $1 + 1;
+ $wait = 1;
if ($limit == 0 || (! $send_response && $next <= $limit)) {
my $rr = new Net::DNS::RR("$1.example.org 86400 $qclass NS ns1.$next.example.org");
push @auth, $rr;
}
}
$rcode = "NOERROR";
+ } elsif ($qname eq "direct.example.net" ) {
+ if ($qtype eq "A") {
+ my ($ttl, $rdata) = (3600, $localaddr);
+ my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata");
+ push @ans, $rr;
+ }
+ $rcode = "NOERROR";
+ } elsif( $qname =~ /^ns1\.(\d+)\.example\.net$/ ) {
+ my $next = ($1 + 1) * 16;
+ for (my $i = 1; $i < 16; $i++) {
+ my $s = $next + $i;
+ my $rr = new Net::DNS::RR("$1.example.net 86400 $qclass NS ns1.$s.example.net");
+ push @auth, $rr;
+ $rr = new Net::DNS::RR("ns1.$s.example.net 86400 $qclass A 10.53.0.7");
+ push @add, $rr;
+ }
+ $rcode = "NOERROR";
} else {
$rcode = "NXDOMAIN";
}
- # mark the answer as authoritive (by setting the 'aa' flag
- return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
+ return ($rcode, \@ans, \@auth, \@add, $wait);
}
-GetOptions(
- 'port=i' => \$localport,
- 'verbose!' => \$verbose,
-);
+sub handleUDP {
+ my ($buf, $peer) = @_;
+ my ($request, $rcode, $ans, $auth, $add, $wait);
+
+ $request = new Net::DNS::Packet(\$buf, 0);
+ $@ and die $@;
+
+ my ($question) = $request->question;
+ my $qname = $question->qname;
+ my $qclass = $question->qclass;
+ my $qtype = $question->qtype;
+
+ ($rcode, $ans, $auth, $add, $wait) = reply_handler($qname, $qclass, $qtype);
+
+ my $reply = $request->reply();
+
+ $reply->header->rcode($rcode);
+ $reply->header->aa(@$ans ? 1 : 0);
+ $reply->header->id($request->header->id);
+ $reply->{answer} = $ans if $ans;
+ $reply->{authority} = $auth if $auth;
+ $reply->{additional} = $add if $add;
+
+ if ($wait) {
+ # reply_handler() asked us to delay sending this reply until
+ # another reply with $wait == 1 is generated or a timeout
+ # occurs.
+ if (@delayed_response) {
+ # A delayed reply is already queued, so we can now send
+ # both the delayed reply and the current reply.
+ send_delayed_response();
+ return $reply;
+ } elsif ($no_more_waiting) {
+ # It was determined before that there is no point in
+ # waiting for "accompanying" queries. Thus, send the
+ # current reply immediately.
+ return $reply;
+ } else {
+ # No delayed reply is queued and the client is expected
+ # to send an "accompanying" query shortly. Do not send
+ # the current reply right now, just save it for later
+ # and wait for an "accompanying" query to be received.
+ @delayed_response = ($reply, $peer);
+ $timeout = 0.5;
+ return;
+ }
+ } else {
+ # Send reply immediately.
+ return $reply;
+ }
+}
-my $ns = Net::DNS::Nameserver->new(
- LocalAddr => $localaddr,
- LocalPort => $localport,
- ReplyHandler => \&reply_handler,
- Verbose => $verbose,
-);
+sub send_delayed_response {
+ my ($reply, $peer) = @delayed_response;
+ # Truncation to 512 bytes is required for triggering "NS explosion" on
+ # builds without IPv6 support
+ $udpsock->send($reply->data(512), 0, $peer);
+ undef @delayed_response;
+ undef $timeout;
+}
-$ns->main_loop;
+# Main
+my $rin;
+my $rout;
+for (;;) {
+ $rin = '';
+ vec($rin, fileno($udpsock), 1) = 1;
+
+ select($rout = $rin, undef, undef, $timeout);
+
+ if (vec($rout, fileno($udpsock), 1)) {
+ my ($buf, $peer, $reply);
+ $udpsock->recv($buf, 512);
+ $peer = $udpsock->peername();
+ $reply = handleUDP($buf, $peer);
+ # Truncation to 512 bytes is required for triggering "NS
+ # explosion" on builds without IPv6 support
+ $udpsock->send($reply->data(512), 0, $peer) if $reply;
+ } else {
+ # An "accompanying" query was expected to come in, but did not.
+ # Assume the client never sends "accompanying" queries to
+ # prevent pointlessly waiting for them ever again.
+ $no_more_waiting = 1;
+ # Send the delayed reply to the query which caused us to wait.
+ send_delayed_response();
+ }
+}
+++ /dev/null
-#!/usr/bin/env perl
-#
-# Copyright (C) 2014, 2016 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/.
-
-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 $count = 0;
-my $send_response = 0;
-
-my $localaddr = "10.53.0.4";
-my $localport = 5300;
-my $verbose = 0;
-
-sub reply_handler {
- my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_;
- my ($rcode, @ans, @auth, @add);
-
- print ("request: $qname/$qtype\n");
- STDOUT->flush();
-
- $count += 1;
-
- if ($qname eq "count" ) {
- if ($qtype eq "TXT") {
- my ($ttl, $rdata) = (0, "$count");
- my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata");
- push @ans, $rr;
- print ("\tcount: $count\n");
- }
- $rcode = "NOERROR";
- } elsif ($qname eq "reset" ) {
- $count = 0;
- $send_response = 0;
- $rcode = "NOERROR";
- } elsif ($qname eq "direct.example.net" ) {
- if ($qtype eq "A") {
- my ($ttl, $rdata) = (3600, $localaddr);
- my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $rdata");
- push @ans, $rr;
- }
- $rcode = "NOERROR";
- } elsif( $qname =~ /^ns1\.(\d+)\.example\.net$/ ) {
- my $next = ($1 + 1) * 16;
- for (my $i = 1; $i < 16; $i++) {
- my $s = $next + $i;
- my $rr = new Net::DNS::RR("$1.example.net 86400 $qclass NS ns1.$s.example.net");
- push @auth, $rr;
- $rr = new Net::DNS::RR("ns1.$s.example.net 86400 $qclass A 10.53.0.7");
- push @add, $rr;
- }
- $rcode = "NOERROR";
- } else {
- $rcode = "NXDOMAIN";
- }
-
- # mark the answer as authoritive (by setting the 'aa' flag
- 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;
example.org. 60 IN NS direct.example.org.
direct.example.org. 60 IN A 10.53.0.2
example.net. 60 IN NS direct.example.net.
-direct.example.net. 60 IN A 10.53.0.4
+direct.example.net. 60 IN A 10.53.0.2
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
+if $PERL -e 'use Net::DNS;' 2>/dev/null
+then
+ if $PERL -e 'use Net::DNS; die if ($Net::DNS::VERSION <= 0.78);' 2>/dev/null
+ then
+ :
+ else
+ echo "I:Net::DNS versions up to 0.78 have a bug that causes this test to fail: please update." >&2
+ exit 1
+ fi
+else
+ echo "I:This test requires the Net::DNS library." >&2
+ exit 1
+fi
+
if $PERL -e 'use Net::DNS::Nameserver;' 2>/dev/null
then
:
status=0
n=0
+ns3_reset() {
+ cp $1 ns3/named.conf
+ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 reconfig 2>&1 | sed 's/^/I:ns3 /'
+ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush | sed 's/^/I: ns3 /'
+}
+
+ns3_sends_aaaa_queries() {
+ if grep "started AAAA fetch" ns3/named.run >/dev/null; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Check whether the number of queries ans2 received from ns3 (this value is
+# read from dig output stored in file $1) is as expected. The expected query
+# count is variable:
+# - if ns3 sends AAAA queries, the query count should equal $2,
+# - if ns3 does not send AAAA queries, the query count should equal $3.
+check_query_count() {
+ count=`sed 's/[^0-9]//g;' $1`
+ expected_count_with_aaaa=$2
+ expected_count_without_aaaa=$3
+
+ if ns3_sends_aaaa_queries; then
+ expected_count=$expected_count_with_aaaa
+ else
+ expected_count=$expected_count_without_aaaa
+ fi
+
+ if [ $count -ne $expected_count ]; then
+ echo "I: count ($count) != $expected_count"
+ ret=1
+ fi
+}
+
+echo "I: set max-recursion-depth=12"
+
n=`expr $n + 1`
-echo "I: attempt excessive-depth lookup ($n)"
+echo "I: attempt excessive-depth lookup ($n)"
ret=0
echo "1000" > ans2/ans.limit
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect1.example.org > dig.out.1.test$n || ret=1
grep "status: SERVFAIL" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
-eval count=`cat dig.out.2.test$n`
-if [ "$TESTSOCK6" != "false" ]
-then
- [ $count -eq 26 ] || { ret=1; echo "I: count ($count) != 26"; }
-else
- [ $count -eq 14 ] || { ret=1; echo "I: count ($count) != 14"; }
-fi
+check_query_count dig.out.2.test$n 26 14
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
-echo "I: attempt permissible lookup ($n)"
+echo "I: attempt permissible lookup ($n)"
ret=0
-sleep 2
echo "12" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named1.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect2.example.org > dig.out.1.test$n || ret=1
grep "status: NOERROR" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
-eval count=`cat dig.out.2.test$n`
-if [ "$TESTSOCK6" != "false" ]
-then
- [ $count -eq 49 ] || { ret=1; echo "I: count ($count) != 49"; }
-else
- [ $count -eq 26 ] || { ret=1; echo "I: count ($count) != 26"; }
-fi
+check_query_count dig.out.2.test$n 49 26
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:reset max-recursion-depth"
-cp ns3/named2.conf ns3/named.conf
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 reconfig 2>&1 | sed 's/^/I:ns1 /'
-sleep 2
+echo "I: set max-recursion-depth=5"
n=`expr $n + 1`
-echo "I: attempt excessive-depth lookup ($n)"
+echo "I: attempt excessive-depth lookup ($n)"
ret=0
echo "12" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named2.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect3.example.org > dig.out.1.test$n || ret=1
grep "status: SERVFAIL" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
-eval count=`cat dig.out.2.test$n`
-if [ "$TESTSOCK6" != "false" ]
-then
- [ $count -eq 12 ] || { ret=1; echo "I: count ($count) != 12"; }
-else
- [ $count -eq 7 ] || { ret=1; echo "I: count ($count) != 7"; }
-fi
+check_query_count dig.out.2.test$n 12 7
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
-echo "I: attempt permissible lookup ($n)"
+echo "I: attempt permissible lookup ($n)"
ret=0
echo "5" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named2.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect4.example.org > dig.out.1.test$n || ret=1
grep "status: NOERROR" dig.out.1.test$n > /dev/null || ret=1
$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
-eval count=`cat dig.out.2.test$n`
-if [ "$TESTSOCK6" != "false" ]
-then
- [ $count -eq 21 ] || { ret=1; echo "I: count ($count) != 21"; }
-else
- [ $count -eq 12 ] || { ret=1; echo "I: count ($count) != 12"; }
-fi
+check_query_count dig.out.2.test$n 21 12
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:reset max-recursion-depth"
-cp ns3/named3.conf ns3/named.conf
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 reconfig 2>&1 | sed 's/^/I:ns1 /'
-sleep 2
+echo "I: set max-recursion-depth=100, max-recursion-queries=50"
n=`expr $n + 1`
-echo "I: attempt excessive-queries lookup ($n)"
+echo "I: attempt excessive-queries lookup ($n)"
ret=0
echo "13" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named3.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect5.example.org > dig.out.1.test$n || ret=1
-if [ "$TESTSOCK6" != "false" ]
-then
+if ns3_sends_aaaa_queries; then
grep "status: SERVFAIL" dig.out.1.test$n > /dev/null || ret=1
fi
$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
status=`expr $status + $ret`
n=`expr $n + 1`
-echo "I: attempt permissible lookup ($n)"
+echo "I: attempt permissible lookup ($n)"
ret=0
echo "12" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named3.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect6.example.org > dig.out.1.test$n || ret=1
grep "status: NOERROR" dig.out.1.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:reset max-recursion-queries"
-cp ns3/named4.conf ns3/named.conf
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 reconfig 2>&1 | sed 's/^/I:ns1 /'
-sleep 2
+echo "I: set max-recursion-depth=100, max-recursion-queries=40"
n=`expr $n + 1`
-echo "I: attempt excessive-queries lookup ($n)"
+echo "I: attempt excessive-queries lookup ($n)"
ret=0
echo "10" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named4.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect7.example.org > dig.out.1.test$n || ret=1
-if [ "$TESTSOCK6" != "false" ]
-then
+if ns3_sends_aaaa_queries; then
grep "status: SERVFAIL" dig.out.1.test$n > /dev/null || ret=1
fi
$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
status=`expr $status + $ret`
n=`expr $n + 1`
-echo "I: attempt permissible lookup ($n)"
+echo "I: attempt permissible lookup ($n)"
ret=0
echo "9" > ans2/ans.limit
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named4.conf
$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS @10.53.0.3 indirect8.example.org > dig.out.1.test$n || ret=1
grep "status: NOERROR" dig.out.1.test$n > /dev/null || ret=1
n=`expr $n + 1`
echo "I: attempting NS explosion ($n)"
ret=0
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 flush 2>&1 | sed 's/^/I:ns1 /'
+ns3_reset ns3/named4.conf
+$DIG $DIGOPTS @10.53.0.2 reset > /dev/null || ret=1
$DIG $DIGOPTS +short @10.53.0.3 ns1.1.example.net > dig.out.1.test$n || ret=1
-sleep 2
-$DIG $DIGOPTS +short @10.53.0.4 count txt > dig.out.2.test$n || ret=1
+$DIG $DIGOPTS +short @10.53.0.2 count txt > dig.out.2.test$n || ret=1
eval count=`cat dig.out.2.test$n`
[ $count -lt 50 ] || ret=1
$DIG $DIGOPTS +short @10.53.0.7 count txt > dig.out.3.test$n || ret=1
* The fetch is waiting for a name to be found.
*/
INSIST(!SHUTTINGDOWN(fctx));
- fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) {
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
want_try = ISC_TRUE;
} else {
fctx->findfail++;
* know the answer. There's nothing to do but
* fail the fctx.
*/
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
want_done = ISC_TRUE;
}
}