From a200b2dd994cbb4ff29151ff46342268bc8fb3c2 Mon Sep 17 00:00:00 2001
From: Evan Hunt <each@isc.org>
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