From 8e014c45ae75a3ca893cec6a0711beb69ecd18a4 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 11 Sep 2017 10:10:16 -0700 Subject: [PATCH] [master] dig: retain domain when retrying with tcp 4712. [bug] "dig +domain" and "dig +search" didn't retain the search domain when retrying with TCP. [RT #45547] --- CHANGES | 3 ++ bin/dig/dighost.c | 4 +-- bin/tests/system/ans.pl | 43 +++++++++++++++++++-------- bin/tests/system/digdelv/ans4/startme | 0 bin/tests/system/digdelv/tests.sh | 13 ++++++++ 5 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 bin/tests/system/digdelv/ans4/startme diff --git a/CHANGES b/CHANGES index 7cfcb7b12a..92cb845c5f 100644 --- 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] diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 5e8b15e28e..c0f7f0466e 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -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); diff --git a/bin/tests/system/ans.pl b/bin/tests/system/ans.pl index 7ec4c8ec74..bd6d2e8bc0 100644 --- a/bin/tests/system/ans.pl +++ b/bin/tests/system/ans.pl @@ -27,7 +27,12 @@ # # 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 index 0000000000..e69de29bb2 diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index 71cce27e98..c2826c5ebb 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -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