From a200b2dd994cbb4ff29151ff46342268bc8fb3c2 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 11 Sep 2017 10:34:10 -0700 Subject: [PATCH 2/2] 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] (cherry picked from commit 8e014c45ae75a3ca893cec6a0711beb69ecd18a4) (cherry picked from commit 88e2cefcc2e8f48c0fba97661ff79c2506b52b23) (cherry picked from commit 51b00c6c783ccf5dca86119ff8f4f8b994298ca4) Modified to pass with libidn Fix origin test --- bin/dig/dighost.c | 13 ++++------- bin/tests/system/ans.pl | 43 +++++++++++++++++++++++++---------- bin/tests/system/digdelv/ans4/startme | 0 bin/tests/system/digdelv/tests.sh | 23 ++++++++++++++++++- 4 files changed, 58 insertions(+), 21 deletions(-) create mode 100644 bin/tests/system/digdelv/ans4/startme diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 5c03d95..3a066c6 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -887,6 +887,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; @@ -2134,6 +2135,7 @@ setup_lookup(dig_lookup_t *lookup) { #ifdef WITH_IDN if (lookup->origin != NULL) { + debug("trying origin %s", lookup->origin->origin); mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->origin->origin, utf8_origin, sizeof(utf8_origin)); @@ -2148,6 +2150,7 @@ setup_lookup(dig_lookup_t *lookup) { idn_check_result(mr, "convert UTF-8 textname to IDN encoding"); #elif defined (WITH_LIBIDN) if (lookup->origin != NULL) { + debug("trying origin %s", lookup->origin->origin); result = libidn_locale_to_utf8 (lookup->origin->origin, utf8_str); check_result (result, "convert origin to UTF-8"); if (len > 0 && utf8_name[len - 1] != '.') { @@ -3409,7 +3407,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; dns_message_destroy(&msg); isc_event_free(&event); clear_query(query); diff --git a/bin/tests/system/ans.pl b/bin/tests/system/ans.pl index d6ff3c2..d8c9f9d 100644 --- a/bin/tests/system/ans.pl +++ b/bin/tests/system/ans.pl @@ -35,7 +35,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, @@ -105,6 +110,9 @@ $SIG{TERM} = \&rmpid; #my @answers = (); my @rules; +my $udphandler; +my $tcphandler; + sub handleUDP { my ($buf) = @_; my $request; @@ -414,8 +422,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)); @@ -430,9 +445,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; @@ -444,12 +461,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 0000000..e69de29 diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index 988bd52..a19256c 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -19,6 +19,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` @@ -62,6 +63,24 @@ 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 + if grep "libidn_locale_to_utf8" dig.out.test$n > /dev/null + then + # libidn patch uses always using root origin, but print also name + grep '^foo\.$' < dig.out.test$n > /dev/null && ret=1 + else + grep "using root origin" < dig.out.test$n > /dev/null && ret=1 + fi + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + else echo "W:$DIG is needed, so skipping these dig tests" fi @@ -131,7 +150,9 @@ if [ -n "${DELV}" -a -x "${DELV}" ] ; then if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` - exit $status else echo "W:${DELV:-delv} is not available, so skipping these delv tests" fi + +echo "I:exit status: $status" +[ $status -eq 0 ] || exit 1 -- 2.9.5