]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] dig: retain domain when retrying with tcp
authorEvan Hunt <each@isc.org>
Mon, 11 Sep 2017 17:10:16 +0000 (10:10 -0700)
committerEvan Hunt <each@isc.org>
Mon, 11 Sep 2017 17:10:16 +0000 (10:10 -0700)
4712. [bug] "dig +domain" and "dig +search" didn't retain the
search domain when retrying with TCP. [RT #45547]

CHANGES
bin/dig/dighost.c
bin/tests/system/ans.pl
bin/tests/system/digdelv/ans4/startme [new file with mode: 0644]
bin/tests/system/digdelv/tests.sh

diff --git a/CHANGES b/CHANGES
index 7cfcb7b12a87ee375b38d32816bbc00aa03300c4..92cb845c5f09a26a58b8b67f388cab983f608812 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4712.  [bug]           "dig +domain" and "dig +search" didn't retain the
+                       search domain when retrying with TCP. [RT #45547]
+
 4711.  [test]          Some RR types were missing from genzones.sh.
                        [RT #45782]
 
index 5e8b15e28e1ae3ae7855756f83f30f2a8555d5bc..c0f7f0466e253b832b8b74620209fc72081dc6cc 100644 (file)
@@ -731,6 +731,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
        looknew->section_answer = lookold->section_answer;
        looknew->section_authority = lookold->section_authority;
        looknew->section_additional = lookold->section_additional;
+       looknew->origin = lookold->origin;
        looknew->retries = lookold->retries;
        looknew->tsigctx = NULL;
        looknew->need_search = lookold->need_search;
@@ -3631,7 +3632,6 @@ recv_done(isc_task_t *task, isc_event_t *event) {
                               newedns);
                l->edns = newedns;
                n = requeue_lookup(l, ISC_TRUE);
-               n->origin = query->lookup->origin;
                if (l->trace && l->trace_root)
                        n->rdtype = l->qrdtype;
                dns_message_destroy(&msg);
@@ -3650,7 +3650,6 @@ recv_done(isc_task_t *task, isc_event_t *event) {
                        printf(";; Truncated, retrying in TCP mode.\n");
                n = requeue_lookup(l, ISC_TRUE);
                n->tcp_mode = ISC_TRUE;
-               n->origin = query->lookup->origin;
                if (l->trace && l->trace_root)
                        n->rdtype = l->qrdtype;
                dns_message_destroy(&msg);
@@ -3672,7 +3671,6 @@ recv_done(isc_task_t *task, isc_event_t *event) {
                        if (l->seenbadcookie)
                                n->tcp_mode = ISC_TRUE;
                        n->seenbadcookie = ISC_TRUE;
-                       n->origin = query->lookup->origin;
                        if (l->trace && l->trace_root)
                                n->rdtype = l->qrdtype;
                        dns_message_destroy(&msg);
index 7ec4c8ec74765d4415239096881583a2c049183e..bd6d2e8bc023f4ef990e5e35fcf4b9e79423a552 100644 (file)
 #
 # There can be any number of patterns, each associated
 # with any number of response RRs.  Each pattern is a
-# Perl regular expression.
+# Perl regular expression.  If an empty pattern ("//") is
+# received, the server will ignore all incoming queries (TCP
+# connections will still be accepted, but both UDP queries
+# and TCP queries will not be responded to).  If a non-empty
+# pattern is then received over the same control connection,
+# default behavior is restored.
 #
 # Each incoming query is converted into a string of the form
 # "qname qtype" (the printable query domain name, space,
@@ -98,6 +103,9 @@ $SIG{TERM} = \&rmpid;
 
 #my @answers = ();
 my @rules;
+my $udphandler;
+my $tcphandler;
+
 sub handleUDP {
        my ($buf) = @_;
        my $request;
@@ -448,8 +456,15 @@ for (;;) {
                while (my $line = $conn->getline) {
                        chomp $line;
                        if ($line =~ m!^/(.*)/$!) {
-                               $rule = { pattern => $1, answer => [] };
-                               push(@rules, $rule);
+                               if (length($1) == 0) {
+                                       $udphandler = sub { return; };
+                                       $tcphandler = sub { return; };
+                               } else {
+                                       $udphandler = \&handleUDP;
+                                       $tcphandler = \&handleTCP;
+                                       $rule = { pattern => $1, answer => [] };
+                                       push(@rules, $rule);
+                               }
                        } else {
                                push(@{$rule->{answer}},
                                     new Net::DNS::RR($line));
@@ -464,9 +479,11 @@ for (;;) {
                printf "UDP request\n";
                my $buf;
                $udpsock->recv($buf, 512);
-               my $result = handleUDP($buf);
-               my $num_chars = $udpsock->send($result);
-               print "  Sent $num_chars bytes via UDP\n";      
+               my $result = &$udphandler($buf);
+               if (defined($result)) {
+                       my $num_chars = $udpsock->send($result);
+                       print "  Sent $num_chars bytes via UDP\n";
+               }
        } elsif (vec($rout, fileno($tcpsock), 1)) {
                my $conn = $tcpsock->accept;
                my $buf;
@@ -478,12 +495,14 @@ for (;;) {
                        $n = $conn->sysread($buf, $len);
                        last unless $n == $len;
                        print "TCP request\n";
-                       my $result = handleTCP($buf);
-                       foreach my $response (@$result) {
-                               $len = length($response);
-                               $n = $conn->syswrite(pack("n", $len), 2);
-                               $n = $conn->syswrite($response, $len);
-                               print "    Sent: $n chars via TCP\n";
+                       my $result = &$tcphandler($buf);
+                       if (defined($result)) {
+                               foreach my $response (@$result) {
+                                       $len = length($response);
+                                       $n = $conn->syswrite(pack("n", $len), 2);
+                                       $n = $conn->syswrite($response, $len);
+                                       print "    Sent: $n chars via TCP\n";
+                               }
                        }
                }
                $conn->close;
diff --git a/bin/tests/system/digdelv/ans4/startme b/bin/tests/system/digdelv/ans4/startme
new file mode 100644 (file)
index 0000000..e69de29
index 71cce27e982a813ba82483d97fbe0f08cbe0f9ea..c2826c5ebb05b141e9875c3b6b6f665c0a60534d 100644 (file)
@@ -11,6 +11,7 @@ status=0
 n=0
 # using dig insecure mode as not testing dnssec here
 DIGOPTS="-i -p 5300"
+SENDCMD="$PERL $SYSTEMTESTTOP/send.pl 10.53.0.4 5301"
 
 if [ -x ${DIG} ] ; then
   n=`expr $n + 1`
@@ -198,6 +199,18 @@ if [ -x ${DIG} ] ; then
   if [ $ret != 0 ]; then echo "I:failed"; fi
   status=`expr $status + $ret`
   
+  n=`expr $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
+  $DIG $DIGOPTS -d +tcp @10.53.0.4 +retry=1 +time=1 +domain=bar foo > dig.out.test$n 2>&1 && ret=1
+  l=`grep "trying origin bar" dig.out.test$n | wc -l`
+  [ ${l:-0} -eq 2 ] || ret=1
+  grep "using root origin" < dig.out.test$n > /dev/null && ret=1
+  if [ $ret != 0 ]; then echo "I:failed"; fi
+  status=`expr $status + $ret`
+
   n=`expr $n + 1`
   echo "I:checking dig -6 -4 ($n)"
   ret=0