mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
[9.20] chg: test: Replace digdelv ans.pl with AsyncDnsServer
Rewrite ans servers in digdelv test to use AsyncDnsServer. Backport of MR !11308 Merge branch 'backport-nicki/asyncdnsserver-digdelv-9.20' into 'bind-9.20' See merge request isc-projects/bind9!11448
This commit is contained in:
commit
8b0d752db2
13 changed files with 305 additions and 625 deletions
25
bin/tests/system/digdelv/ans4/ans.py
Normal file
25
bin/tests/system/digdelv/ans4/ans.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from isctest.asyncserver import (
|
||||
AsyncDnsServer,
|
||||
IgnoreAllQueries,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer()
|
||||
server.install_response_handler(IgnoreAllQueries())
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
# This is a TCP-only DNS server whose aim is to facilitate testing how dig
|
||||
# copes with prematurely closed TCP connections.
|
||||
#
|
||||
# This server can be configured (through a separate control socket) with a
|
||||
# series of responses to send for subsequent incoming TCP DNS queries. Only
|
||||
# one query is handled before closing each connection. In order to keep things
|
||||
# simple, the server is not equipped with any mechanism for handling malformed
|
||||
# queries.
|
||||
#
|
||||
# Available response types are defined in the %response_types hash in the
|
||||
# getAnswerSection() function below. Each RR returned is generated dynamically
|
||||
# based on the QNAME found in the incoming query.
|
||||
|
||||
use IO::File;
|
||||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
use strict;
|
||||
|
||||
# Ignore SIGPIPE so we won't fail if peer closes a TCP socket early
|
||||
local $SIG{PIPE} = 'IGNORE';
|
||||
|
||||
# Flush logged output after every line
|
||||
local $| = 1;
|
||||
|
||||
my $server_addr = "10.53.0.5";
|
||||
if (@ARGV > 0) {
|
||||
$server_addr = @ARGV[0];
|
||||
}
|
||||
|
||||
my $mainport = int($ENV{'PORT'});
|
||||
if (!$mainport) { $mainport = 5300; }
|
||||
my $ctrlport = int($ENV{'EXTRAPORT1'});
|
||||
if (!$ctrlport) { $ctrlport = 5301; }
|
||||
|
||||
my $ctlsock = IO::Socket::INET->new(LocalAddr => "$server_addr",
|
||||
LocalPort => $ctrlport, Proto => "tcp", Listen => 5, Reuse => 1) or die "$!";
|
||||
|
||||
my $tcpsock = IO::Socket::INET->new(LocalAddr => "$server_addr",
|
||||
LocalPort => $mainport, Proto => "tcp", Listen => 5, 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: $!";
|
||||
$pidf->close or die "cannot close pid file: $!";;
|
||||
sub rmpid { unlink "ans.pid"; exit 1; };
|
||||
|
||||
$SIG{INT} = \&rmpid;
|
||||
$SIG{TERM} = \&rmpid;
|
||||
|
||||
my @response_sequence = ("complete_axfr");
|
||||
my $connection_counter = 0;
|
||||
|
||||
# Return the next answer type to send, incrementing the connection counter and
|
||||
# making sure the latter does not exceed the size of the array holding the
|
||||
# configured response sequence.
|
||||
sub getNextResponseType {
|
||||
my $response_type = $response_sequence[$connection_counter];
|
||||
|
||||
$connection_counter++;
|
||||
$connection_counter %= scalar(@response_sequence);
|
||||
|
||||
return $response_type;
|
||||
}
|
||||
|
||||
# Return an array of resource records comprising the answer section of a given
|
||||
# response type.
|
||||
sub getAnswerSection {
|
||||
my ($response_type, $qname) = @_;
|
||||
|
||||
my %response_types = (
|
||||
no_response => [],
|
||||
|
||||
partial_axfr => [
|
||||
Net::DNS::RR->new("$qname 300 IN SOA . . 0 0 0 0 300"),
|
||||
Net::DNS::RR->new("$qname NS ."),
|
||||
],
|
||||
|
||||
complete_axfr => [
|
||||
Net::DNS::RR->new("$qname 300 IN SOA . . 0 0 0 0 300"),
|
||||
Net::DNS::RR->new("$qname NS ."),
|
||||
Net::DNS::RR->new("$qname 300 IN SOA . . 0 0 0 0 300"),
|
||||
],
|
||||
);
|
||||
|
||||
return $response_types{$response_type};
|
||||
}
|
||||
|
||||
|
||||
# Generate a Net::DNS::Packet containing the response to send on the current
|
||||
# TCP connection. If the answer section of the response is determined to be
|
||||
# empty, no data will be sent on the connection at all (immediate EOF).
|
||||
sub generateResponse {
|
||||
my ($buf) = @_;
|
||||
my $request;
|
||||
|
||||
if ($Net::DNS::VERSION > 0.68) {
|
||||
$request = new Net::DNS::Packet(\$buf, 0);
|
||||
$@ and die $@;
|
||||
} else {
|
||||
my $err;
|
||||
($request, $err) = new Net::DNS::Packet(\$buf, 0);
|
||||
$err and die $err;
|
||||
}
|
||||
|
||||
my @questions = $request->question;
|
||||
my $qname = $questions[0]->qname;
|
||||
my $qtype = $questions[0]->qtype;
|
||||
my $qclass = $questions[0]->qclass;
|
||||
my $id = $request->header->id;
|
||||
|
||||
my $packet = new Net::DNS::Packet($qname, $qtype, $qclass);
|
||||
$packet->header->qr(1);
|
||||
$packet->header->aa(1);
|
||||
$packet->header->id($id);
|
||||
|
||||
my $response_type = getNextResponseType();
|
||||
my $answers = getAnswerSection($response_type, $qname);
|
||||
for my $rr (@$answers) {
|
||||
$packet->push("answer", $rr);
|
||||
}
|
||||
|
||||
print " Sending \"$response_type\" response\n";
|
||||
|
||||
return $packet->data if @$answers;
|
||||
}
|
||||
|
||||
my $rin;
|
||||
my $rout;
|
||||
for (;;) {
|
||||
$rin = '';
|
||||
vec($rin, fileno($ctlsock), 1) = 1;
|
||||
vec($rin, fileno($tcpsock), 1) = 1;
|
||||
|
||||
select($rout = $rin, undef, undef, undef);
|
||||
|
||||
if (vec($rout, fileno($ctlsock), 1)) {
|
||||
my $conn = $ctlsock->accept;
|
||||
@response_sequence = split(' ', $conn->getline);
|
||||
$connection_counter = 0;
|
||||
print "Response sequence set to: @response_sequence\n";
|
||||
$conn->close;
|
||||
} elsif (vec($rout, fileno($tcpsock), 1)) {
|
||||
my $buf;
|
||||
my $lenbuf;
|
||||
my $conn = $tcpsock->accept;
|
||||
my $n = $conn->sysread($lenbuf, 2);
|
||||
die unless $n == 2;
|
||||
my $len = unpack("n", $lenbuf);
|
||||
$n = $conn->sysread($buf, $len);
|
||||
die unless $n == $len;
|
||||
print "TCP request\n";
|
||||
my $response = generateResponse($buf);
|
||||
if ($response) {
|
||||
$len = length($response);
|
||||
$n = $conn->syswrite(pack("n", $len), 2);
|
||||
$n = $conn->syswrite($response, $len);
|
||||
print " Sent: $n chars via TCP\n";
|
||||
} else {
|
||||
print " No response sent\n";
|
||||
}
|
||||
$conn->close;
|
||||
}
|
||||
}
|
||||
104
bin/tests/system/digdelv/ans5/ans.py
Normal file
104
bin/tests/system/digdelv/ans5/ans.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
import logging
|
||||
from typing import AsyncGenerator, List, Optional
|
||||
|
||||
import dns.rcode
|
||||
import dns.rdatatype
|
||||
import dns.rrset
|
||||
|
||||
from isctest.asyncserver import (
|
||||
CloseConnection,
|
||||
ControlCommand,
|
||||
ControllableAsyncDnsServer,
|
||||
DnsResponseSend,
|
||||
QueryContext,
|
||||
ResponseAction,
|
||||
ResponseHandler,
|
||||
)
|
||||
|
||||
|
||||
class ErraticAxfrHandler(ResponseHandler):
|
||||
allowed_actions = ["no-response", "partial-axfr", "complete-axfr"]
|
||||
|
||||
def __init__(self, actions: List[str]) -> None:
|
||||
self.actions = actions
|
||||
self.counter = 0
|
||||
for action in actions:
|
||||
assert action in self.allowed_actions
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[ResponseAction, None]:
|
||||
action = self.actions[self.counter % len(self.actions)]
|
||||
self.counter += 1
|
||||
|
||||
logging.info("current response action: %s", action)
|
||||
|
||||
if action == "no-response":
|
||||
yield CloseConnection()
|
||||
return
|
||||
|
||||
soa_rr = dns.rrset.from_text(
|
||||
qctx.qname, 300, qctx.qclass, dns.rdatatype.SOA, ". . 0 0 0 0 300"
|
||||
)
|
||||
ns_rr = dns.rrset.from_text(qctx.qname, 300, qctx.qclass, dns.rdatatype.NS, ".")
|
||||
|
||||
qctx.response.answer.append(soa_rr)
|
||||
qctx.response.answer.append(ns_rr)
|
||||
|
||||
if action == "partial-axfr":
|
||||
yield DnsResponseSend(qctx.response)
|
||||
elif action == "complete-axfr":
|
||||
qctx.response.answer.append(soa_rr)
|
||||
yield DnsResponseSend(qctx.response)
|
||||
yield CloseConnection()
|
||||
|
||||
|
||||
class ResponseSequenceCommand(ControlCommand):
|
||||
control_subdomain = "response-sequence"
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._current_handler: Optional[ResponseHandler] = None
|
||||
|
||||
def handle(
|
||||
self, args: List[str], server: ControllableAsyncDnsServer, qctx: QueryContext
|
||||
) -> str:
|
||||
for action in args:
|
||||
if action not in ErraticAxfrHandler.allowed_actions:
|
||||
logging.error("invalid %s action '%s'", self, action)
|
||||
qctx.response.set_rcode(dns.rcode.SERVFAIL)
|
||||
return f"invalid action '{action}'; must be one of {ErraticAxfrHandler.allowed_actions}"
|
||||
|
||||
actions = args
|
||||
|
||||
if self._current_handler is not None:
|
||||
server.uninstall_response_handler(self._current_handler)
|
||||
|
||||
self._current_handler = ErraticAxfrHandler(actions)
|
||||
server.install_response_handler(self._current_handler)
|
||||
|
||||
msg = f"reponse sequence set to {actions}"
|
||||
logging.info(msg)
|
||||
return msg
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = ControllableAsyncDnsServer(
|
||||
default_aa=True, default_rcode=dns.rcode.NOERROR
|
||||
)
|
||||
server.install_control_command(ResponseSequenceCommand())
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
use IO::File;
|
||||
use IO::Socket;
|
||||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
my $localport = int($ENV{'PORT'});
|
||||
if (!$localport) { $localport = 5300; }
|
||||
|
||||
my $sock = IO::Socket::INET->new(LocalAddr => "10.53.0.6",
|
||||
LocalPort => $localport, Proto => "udp") 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: $!";
|
||||
$pidf->close or die "cannot close pid file: $!";
|
||||
sub rmpid { unlink "ans.pid"; exit 1; };
|
||||
|
||||
$SIG{INT} = \&rmpid;
|
||||
$SIG{TERM} = \&rmpid;
|
||||
|
||||
for (;;) {
|
||||
$sock->recv($buf, 512);
|
||||
|
||||
print "**** request from " , $sock->peerhost, " port ", $sock->peerport, "\n";
|
||||
|
||||
my $packet;
|
||||
|
||||
if ($Net::DNS::VERSION > 0.68) {
|
||||
$packet = new Net::DNS::Packet(\$buf, 0);
|
||||
$@ and die $@;
|
||||
} else {
|
||||
my $err;
|
||||
($packet, $err) = new Net::DNS::Packet(\$buf, 0);
|
||||
$err and die $err;
|
||||
}
|
||||
|
||||
print "REQUEST:\n";
|
||||
$packet->print;
|
||||
|
||||
$packet->header->qr(1);
|
||||
|
||||
my @questions = $packet->question;
|
||||
my $qname = $questions[0]->qname;
|
||||
my $qtype = $questions[0]->qtype;
|
||||
|
||||
my $donotrespond = 0;
|
||||
|
||||
$packet->header->aa(1);
|
||||
if ($qtype eq "A") {
|
||||
$packet->push("answer",
|
||||
new Net::DNS::RR($qname . " 300 A 10.53.0.5"));
|
||||
} else {
|
||||
$donotrespond = 1;
|
||||
}
|
||||
|
||||
if ($donotrespond == 0) {
|
||||
my $sendsock =
|
||||
IO::Socket::INET->new(LocalAddr => "10.53.1.2",
|
||||
PeerAddr => $sock->peerhost,
|
||||
PeerPort => $sock->peerport,
|
||||
Proto => "udp") or die "$!";
|
||||
print "**** response from ", $sendsock->sockhost, " to " ,
|
||||
$sendsock->peerhost, " port ", $sendsock->peerport, "\n";
|
||||
$sendsock->send($packet->data);
|
||||
$sendsock->close;
|
||||
print "RESPONSE:\n";
|
||||
$packet->print;
|
||||
print "\n";
|
||||
} else {
|
||||
print "DROP:\n";
|
||||
}
|
||||
}
|
||||
40
bin/tests/system/digdelv/ans6/ans.py
Normal file
40
bin/tests/system/digdelv/ans6/ans.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from typing import AsyncGenerator
|
||||
|
||||
import dns.opcode
|
||||
import dns.rcode
|
||||
|
||||
from isctest.asyncserver import (
|
||||
AsyncDnsServer,
|
||||
DnsResponseSend,
|
||||
ResponseHandler,
|
||||
QueryContext,
|
||||
)
|
||||
|
||||
|
||||
class ReplyUpdateHandler(ResponseHandler):
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[DnsResponseSend, None]:
|
||||
qctx.response.set_opcode(dns.opcode.UPDATE)
|
||||
yield DnsResponseSend(qctx.response)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer(default_aa=True, default_rcode=dns.rcode.NOERROR)
|
||||
server.install_response_handler(ReplyUpdateHandler())
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
use IO::File;
|
||||
use IO::Socket;
|
||||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
my $localport = int($ENV{'PORT'});
|
||||
if (!$localport) { $localport = 5300; }
|
||||
|
||||
my $sock = IO::Socket::INET->new(LocalAddr => "10.53.0.7",
|
||||
LocalPort => $localport, Proto => "udp") 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: $!";
|
||||
$pidf->close or die "cannot close pid file: $!";
|
||||
sub rmpid { unlink "ans.pid"; exit 1; };
|
||||
|
||||
$SIG{INT} = \&rmpid;
|
||||
$SIG{TERM} = \&rmpid;
|
||||
|
||||
STDOUT->autoflush(1);
|
||||
|
||||
print "Net::DNS::VERSION => $Net::DNS::VERSION\n";
|
||||
|
||||
for (;;) {
|
||||
$sock->recv($buf, 512);
|
||||
|
||||
print "**** request from " , $sock->peerhost, " port ", $sock->peerport, "\n";
|
||||
|
||||
my $packet;
|
||||
|
||||
if ($Net::DNS::VERSION > 0.68) {
|
||||
$packet = new Net::DNS::Packet(\$buf, 0);
|
||||
$@ and die $@;
|
||||
} else {
|
||||
my $err;
|
||||
($packet, $err) = new Net::DNS::Packet(\$buf, 0);
|
||||
$err and die $err;
|
||||
}
|
||||
|
||||
print "REQUEST:\n";
|
||||
$packet->print;
|
||||
|
||||
$packet->header->qr(1);
|
||||
$packet->header->opcode(5);
|
||||
|
||||
my @questions = $packet->question;
|
||||
my $qname = $questions[0]->qname;
|
||||
my $qtype = $questions[0]->qtype;
|
||||
$packet->push("update", rr_del("$qname SOA"));
|
||||
|
||||
print "RESPONSE:\n";
|
||||
$packet->print;
|
||||
|
||||
$sock->send($packet->data);
|
||||
}
|
||||
76
bin/tests/system/digdelv/ans7/ans.py
Normal file
76
bin/tests/system/digdelv/ans7/ans.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from typing import AsyncGenerator
|
||||
|
||||
import dns
|
||||
import dns.rcode
|
||||
|
||||
from isctest.asyncserver import (
|
||||
AsyncDnsServer,
|
||||
CloseConnection,
|
||||
DnsResponseSend,
|
||||
DomainHandler,
|
||||
IgnoreAllQueries,
|
||||
QueryContext,
|
||||
ResponseAction,
|
||||
ResponseDrop,
|
||||
)
|
||||
|
||||
|
||||
class SilentHandler(DomainHandler, IgnoreAllQueries):
|
||||
"""Handler that doesn't respond."""
|
||||
|
||||
domains = ["silent.example"]
|
||||
|
||||
|
||||
class CloseHandler(DomainHandler):
|
||||
"""Handler that doesn't respond and closes TCP connection."""
|
||||
|
||||
domains = ["close.example"]
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[ResponseAction, None]:
|
||||
yield CloseConnection()
|
||||
|
||||
|
||||
class SilentThenServfailHandler(DomainHandler):
|
||||
"""Handler that drops one query and response to the next one with SERVFAIL."""
|
||||
|
||||
domains = ["silent-then-servfail.example"]
|
||||
counter = 0
|
||||
|
||||
async def get_responses(
|
||||
self, qctx: QueryContext
|
||||
) -> AsyncGenerator[ResponseAction, None]:
|
||||
if self.counter % 2 == 0:
|
||||
yield ResponseDrop()
|
||||
else:
|
||||
qctx.response.set_rcode(dns.rcode.SERVFAIL)
|
||||
yield DnsResponseSend(qctx.response, authoritative=False)
|
||||
self.counter += 1
|
||||
|
||||
|
||||
def main() -> None:
|
||||
server = AsyncDnsServer()
|
||||
server.install_response_handlers(
|
||||
[
|
||||
CloseHandler(),
|
||||
SilentHandler(),
|
||||
SilentThenServfailHandler(),
|
||||
]
|
||||
)
|
||||
server.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# 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 https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import signal
|
||||
import socket
|
||||
import select
|
||||
import struct
|
||||
|
||||
import dns, dns.message
|
||||
from dns.rcode import *
|
||||
|
||||
modes = [
|
||||
b"silent", # Do not respond
|
||||
b"close", # UDP: same as silent; TCP: also close the connection
|
||||
b"servfail", # Always respond with SERVFAIL
|
||||
b"unstable", # Constantly switch between "silent" and "servfail"
|
||||
]
|
||||
mode = modes[0]
|
||||
n = 0
|
||||
|
||||
|
||||
def ctrl_channel(msg):
|
||||
global modes, mode, n
|
||||
|
||||
msg = msg.splitlines().pop(0)
|
||||
print("Received control message: %s" % msg)
|
||||
|
||||
if msg in modes:
|
||||
mode = msg
|
||||
n = 0
|
||||
print("New mode: %s" % str(mode))
|
||||
|
||||
|
||||
def create_servfail(msg):
|
||||
m = dns.message.from_wire(msg)
|
||||
qname = m.question[0].name.to_text()
|
||||
rrtype = m.question[0].rdtype
|
||||
typename = dns.rdatatype.to_text(rrtype)
|
||||
|
||||
with open("query.log", "a") as f:
|
||||
f.write("%s %s\n" % (typename, qname))
|
||||
print("%s %s" % (typename, qname), end=" ")
|
||||
|
||||
r = dns.message.make_response(m)
|
||||
r.set_rcode(SERVFAIL)
|
||||
return r
|
||||
|
||||
|
||||
def sigterm(signum, frame):
|
||||
print("Shutting down now...")
|
||||
os.remove("ans.pid")
|
||||
running = False
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
ip4 = "10.53.0.8"
|
||||
|
||||
try:
|
||||
port = int(os.environ["PORT"])
|
||||
except:
|
||||
port = 5300
|
||||
|
||||
try:
|
||||
ctrlport = int(os.environ["EXTRAPORT1"])
|
||||
except:
|
||||
ctrlport = 5300
|
||||
|
||||
query4_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
query4_udp.bind((ip4, port))
|
||||
|
||||
query4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
query4_tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
query4_tcp.bind((ip4, port))
|
||||
query4_tcp.listen(100)
|
||||
|
||||
ctrl4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ctrl4_tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
ctrl4_tcp.bind((ip4, ctrlport))
|
||||
ctrl4_tcp.listen(100)
|
||||
|
||||
signal.signal(signal.SIGTERM, sigterm)
|
||||
|
||||
f = open("ans.pid", "w")
|
||||
pid = os.getpid()
|
||||
print(pid, file=f)
|
||||
f.close()
|
||||
|
||||
running = True
|
||||
|
||||
print("Listening on %s port %d" % (ip4, port))
|
||||
print("Listening on %s port %d" % (ip4, ctrlport))
|
||||
print("Ctrl-c to quit")
|
||||
|
||||
input = [query4_udp, query4_tcp, ctrl4_tcp]
|
||||
|
||||
hung_conns = []
|
||||
|
||||
while running:
|
||||
try:
|
||||
inputready, outputready, exceptready = select.select(input, [], [])
|
||||
except select.error as e:
|
||||
break
|
||||
except socket.error as e:
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
for s in inputready:
|
||||
if s == query4_udp:
|
||||
n = n + 1
|
||||
print("UDP query received on %s" % ip4, end=" ")
|
||||
msg = s.recvfrom(65535)
|
||||
if (
|
||||
mode == b"silent"
|
||||
or mode == b"close"
|
||||
or (mode == b"unstable" and n % 2 == 1)
|
||||
):
|
||||
# Do not respond.
|
||||
print("NO RESPONSE (%s)" % str(mode))
|
||||
continue
|
||||
elif mode == b"servfail" or (mode == b"unstable" and n % 2 == 0):
|
||||
rsp = create_servfail(msg[0])
|
||||
if rsp:
|
||||
print(dns.rcode.to_text(rsp.rcode()))
|
||||
s.sendto(rsp.to_wire(), msg[1])
|
||||
else:
|
||||
print("NO RESPONSE (can not create a response)")
|
||||
else:
|
||||
raise (Exception("unsupported mode: %s" % mode))
|
||||
elif s == query4_tcp:
|
||||
n = n + 1
|
||||
print("TCP query received on %s" % ip4, end=" ")
|
||||
conn = None
|
||||
try:
|
||||
if mode == b"silent" or (mode == b"unstable" and n % 2 == 1):
|
||||
conn, addr = s.accept()
|
||||
# Do not respond and hang the connection.
|
||||
print("NO RESPONSE (%s)" % str(mode))
|
||||
hung_conns.append(conn)
|
||||
continue
|
||||
elif mode == b"close":
|
||||
conn, addr = s.accept()
|
||||
# Do not respond and close the connection.
|
||||
print("NO RESPONSE (%s)" % str(mode))
|
||||
conn.close()
|
||||
continue
|
||||
elif mode == b"servfail" or (mode == b"unstable" and n % 2 == 0):
|
||||
conn, addr = s.accept()
|
||||
# get TCP message length
|
||||
msg = conn.recv(2)
|
||||
if len(msg) != 2:
|
||||
print("NO RESPONSE (can not read the message length)")
|
||||
conn.close()
|
||||
continue
|
||||
length = struct.unpack(">H", msg[:2])[0]
|
||||
msg = conn.recv(length)
|
||||
if len(msg) != length:
|
||||
print("NO RESPONSE (can not read the message)")
|
||||
conn.close()
|
||||
continue
|
||||
rsp = create_servfail(msg)
|
||||
if rsp:
|
||||
print(dns.rcode.to_text(rsp.rcode()))
|
||||
wire = rsp.to_wire()
|
||||
conn.send(struct.pack(">H", len(wire)))
|
||||
conn.send(wire)
|
||||
else:
|
||||
print("NO RESPONSE (can not create a response)")
|
||||
else:
|
||||
raise (Exception("unsupported mode: %s" % mode))
|
||||
except socket.error as e:
|
||||
print("NO RESPONSE (error: %s)" % str(e))
|
||||
if conn:
|
||||
conn.close()
|
||||
elif s == ctrl4_tcp:
|
||||
print("Control channel connected")
|
||||
conn = None
|
||||
try:
|
||||
# Handle control channel input
|
||||
conn, addr = s.accept()
|
||||
msg = conn.recv(1024)
|
||||
if msg:
|
||||
ctrl_channel(msg)
|
||||
conn.close()
|
||||
except s.timeout:
|
||||
pass
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
if not running:
|
||||
break
|
||||
|
|
@ -33,6 +33,9 @@ c AAAA fd92:7065:b8e:ffff::3
|
|||
d A 10.0.0.0
|
||||
d AAAA fd92:7065:b8e:ffff::
|
||||
|
||||
silent A 10.0.0.1
|
||||
close A 10.0.0.1
|
||||
|
||||
xn--caf-dma A 10.1.2.3
|
||||
|
||||
foo TXT "testing"
|
||||
|
|
|
|||
|
|
@ -19,10 +19,6 @@ set -e
|
|||
status=0
|
||||
n=0
|
||||
|
||||
sendcmd() {
|
||||
send "${1}" "$EXTRAPORT1"
|
||||
}
|
||||
|
||||
dig_with_opts() {
|
||||
"$DIG" -p "$PORT" "$@"
|
||||
}
|
||||
|
|
@ -31,6 +27,12 @@ mdig_with_opts() {
|
|||
"$MDIG" -p "$PORT" "$@"
|
||||
}
|
||||
|
||||
set_response_sequence() {
|
||||
SEQUENCE="${1}"
|
||||
LOGID="${2}"
|
||||
dig_with_opts @10.53.0.5 "${SEQUENCE}.response-sequence._control" TXT >dig.out.control${LOGID} 2>&1 || ret=1
|
||||
}
|
||||
|
||||
# Check if response in file $1 has the correct TTL range.
|
||||
# The response record must have RRtype $2 and class IN (CLASS1).
|
||||
# Maximum TTL is given by $3. This works in most cases where TTL is
|
||||
|
|
@ -71,72 +73,44 @@ NOSPLIT="$(sed <ns2/keydata -e 's/+/[+]/g' -e 's/ //g')"
|
|||
HAS_PYYAML=0
|
||||
$PYTHON -c "import yaml" 2>/dev/null && HAS_PYYAML=1
|
||||
|
||||
#
|
||||
# test whether ans7/ans.pl will be able to send a UPDATE response.
|
||||
# if it can't, we will log that below.
|
||||
#
|
||||
if "$PERL" -e 'use Net::DNS; use Net::DNS::Packet; my $p = new Net::DNS::Packet; $p->header->opcode(5);' >/dev/null 2>&1; then
|
||||
checkupdate=1
|
||||
else
|
||||
checkupdate=0
|
||||
fi
|
||||
n=$((n + 1))
|
||||
echo_i "check nslookup handles UPDATE response ($n)"
|
||||
ret=0
|
||||
"$NSLOOKUP" -q=CNAME -timeout=1 "-port=$PORT" foo.bar 10.53.0.6 >nslookup.out.test$n 2>&1 && ret=1
|
||||
grep "Opcode mismatch" nslookup.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if [ -x "$NSLOOKUP" -a $checkupdate -eq 1 ]; then
|
||||
n=$((n + 1))
|
||||
echo_i "check host handles UPDATE response ($n)"
|
||||
ret=0
|
||||
"$HOST" -W 1 -t CNAME -p $PORT foo.bar 10.53.0.6 >host.out.test$n 2>&1 && ret=1
|
||||
grep "Opcode mismatch" host.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check nslookup handles UPDATE response ($n)"
|
||||
ret=0
|
||||
"$NSLOOKUP" -q=CNAME -timeout=1 "-port=$PORT" foo.bar 10.53.0.7 >nslookup.out.test$n 2>&1 && ret=1
|
||||
grep "Opcode mismatch" nslookup.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
fi
|
||||
|
||||
if [ -x "$HOST" -a $checkupdate -eq 1 ]; then
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check host handles UPDATE response ($n)"
|
||||
ret=0
|
||||
"$HOST" -W 1 -t CNAME -p $PORT foo.bar 10.53.0.7 >host.out.test$n 2>&1 && ret=1
|
||||
grep "Opcode mismatch" host.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
fi
|
||||
|
||||
if [ -x "$NSUPDATE" -a $checkupdate -eq 1 ]; then
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check nsupdate handles UPDATE response to QUERY ($n)"
|
||||
ret=0
|
||||
res=0
|
||||
$NSUPDATE <<EOF >nsupdate.out.test$n 2>&1 || res=$?
|
||||
server 10.53.0.7 ${PORT}
|
||||
n=$((n + 1))
|
||||
echo_i "check nsupdate handles UPDATE response to QUERY ($n)"
|
||||
ret=0
|
||||
res=0
|
||||
$NSUPDATE <<EOF >nsupdate.out.test$n 2>&1 || res=$?
|
||||
server 10.53.0.6 ${PORT}
|
||||
add x.example.com 300 in a 1.2.3.4
|
||||
send
|
||||
EOF
|
||||
test $res -eq 1 || ret=1
|
||||
grep "invalid OPCODE in response to SOA query" nsupdate.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
fi
|
||||
test $res -eq 1 || ret=1
|
||||
grep "invalid OPCODE in response to SOA query" nsupdate.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if [ -x "$DIG" ]; then
|
||||
|
||||
if [ $checkupdate -eq 1 ]; then
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check dig handles UPDATE response ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.7 +tries=1 +timeout=1 cname foo.bar >dig.out.test$n 2>&1 && ret=1
|
||||
grep "Opcode mismatch" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
else
|
||||
echo_i "Skipped UPDATE handling test"
|
||||
fi
|
||||
n=$((n + 1))
|
||||
echo_i "check dig handles UPDATE response ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.6 +tries=1 +timeout=1 cname foo.bar >dig.out.test$n 2>&1 && ret=1
|
||||
grep "Opcode mismatch" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig short form works ($n)"
|
||||
|
|
@ -382,8 +356,6 @@ if [ -x "$DIG" ]; then
|
|||
n=$((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 10.53.0.4
|
||||
dig_with_opts -d +tcp @10.53.0.4 +retry=1 +time=1 +domain=bar foo >dig.out.test$n 2>&1 && ret=1
|
||||
test "$(grep -c "trying origin bar" dig.out.test$n)" -eq 2 || ret=1
|
||||
grep "using root origin" <dig.out.test$n >/dev/null && ret=1
|
||||
|
|
@ -1042,7 +1014,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking exit code for a retry upon TCP EOF (immediate -> immediate) ($n)"
|
||||
ret=0
|
||||
echo "no_response no_response" | sendcmd 10.53.0.5
|
||||
set_response_sequence no-response $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1
|
||||
|
|
@ -1052,7 +1024,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> partial AXFR) ($n)"
|
||||
ret=0
|
||||
echo "partial_axfr partial_axfr" | sendcmd 10.53.0.5
|
||||
set_response_sequence partial-axfr $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1
|
||||
|
|
@ -1062,7 +1034,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking exit code for a retry upon TCP EOF (immediate -> partial AXFR) ($n)"
|
||||
ret=0
|
||||
echo "no_response partial_axfr" | sendcmd 10.53.0.5
|
||||
set_response_sequence no-response.partial-axfr $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1
|
||||
|
|
@ -1072,7 +1044,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> immediate) ($n)"
|
||||
ret=0
|
||||
echo "partial_axfr no_response" | sendcmd 10.53.0.5
|
||||
set_response_sequence partial-axfr.no-response $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 && ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 2 ] || ret=1
|
||||
|
|
@ -1082,7 +1054,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking exit code for a retry upon TCP EOF (immediate -> complete AXFR) ($n)"
|
||||
ret=0
|
||||
echo "no_response complete_axfr" | sendcmd 10.53.0.5
|
||||
set_response_sequence no-response.complete-axfr $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 || ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1
|
||||
|
|
@ -1092,7 +1064,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking exit code for a retry upon TCP EOF (partial AXFR -> complete AXFR) ($n)"
|
||||
ret=0
|
||||
echo "partial_axfr complete_axfr" | sendcmd 10.53.0.5
|
||||
set_response_sequence partial-axfr.complete-axfr $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=2 >dig.out.test$n 2>&1 || ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1
|
||||
|
|
@ -1102,7 +1074,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "checking +tries=1 won't retry twice upon TCP EOF ($n)"
|
||||
ret=0
|
||||
echo "no_response no_response" | sendcmd 10.53.0.5
|
||||
set_response_sequence no-response $n
|
||||
dig_with_opts @10.53.0.5 example AXFR +tries=1 >dig.out.test$n 2>&1 && ret=1
|
||||
# Sanity check: ensure ans5 behaves as expected.
|
||||
[ $(grep "communications error.*end of file" dig.out.test$n | wc -l) -eq 1 ] || ret=1
|
||||
|
|
@ -1236,20 +1208,16 @@ if [ -x "$DIG" ]; then
|
|||
# See [GL #3020] for more information
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig handles UDP timeout followed by a SERVFAIL correctly ($n)"
|
||||
# Ask ans8 to be in "unstable" mode (switching between "silent" and "servfail" modes)
|
||||
echo "unstable" | sendcmd 10.53.0.8
|
||||
ret=0
|
||||
dig_with_opts +timeout=1 +nofail @10.53.0.8 a.example >dig.out.test$n 2>&1 || ret=1
|
||||
dig_with_opts +timeout=1 +nofail @10.53.0.7 silent-then-servfail.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep -F "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig handles TCP timeout followed by a SERVFAIL correctly ($n)"
|
||||
# Ask ans8 to be in "unstable" mode (switching between "silent" and "servfail" modes)
|
||||
echo "unstable" | sendcmd 10.53.0.8
|
||||
ret=0
|
||||
dig_with_opts +timeout=1 +nofail +tcp @10.53.0.8 a.example >dig.out.test$n 2>&1 || ret=1
|
||||
dig_with_opts +timeout=1 +nofail +tcp @10.53.0.7 silent-then-servfail.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep -F "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
|
@ -1282,10 +1250,8 @@ if [ -x "$DIG" ]; then
|
|||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig tries the next server after a TCP socket read error ($n)"
|
||||
# Ask ans8 to be in "close" mode, which closes the connection after accepting it
|
||||
echo "close" | sendcmd 10.53.0.8
|
||||
ret=0
|
||||
dig_with_opts +tcp @10.53.0.8 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1
|
||||
dig_with_opts +tcp @10.53.0.7 @10.53.0.3 close.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
|
@ -1307,20 +1273,16 @@ if [ -x "$DIG" ]; then
|
|||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig tries the next server after UDP socket read timeouts ($n)"
|
||||
# Ask ans8 to be in "silent" mode
|
||||
echo "silent" | sendcmd 10.53.0.8
|
||||
ret=0
|
||||
dig_with_opts +timeout=1 @10.53.0.8 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1
|
||||
dig_with_opts +timeout=1 @10.53.0.7 @10.53.0.3 silent.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig tries the next server after TCP socket read timeouts ($n)"
|
||||
# Ask ans8 to be in "silent" mode
|
||||
echo "silent" | sendcmd 10.53.0.8
|
||||
ret=0
|
||||
dig_with_opts +timeout=1 +tcp @10.53.0.8 @10.53.0.3 a.example >dig.out.test$n 2>&1 || ret=1
|
||||
dig_with_opts +timeout=1 +tcp @10.53.0.7 @10.53.0.3 silent.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep -F "status: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
|
@ -1329,7 +1291,7 @@ if [ -x "$DIG" ]; then
|
|||
n=$((n + 1))
|
||||
echo_i "check that dig correctly refuses to use a server with a IPv4 mapped IPv6 address after failing with a regular IP address ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.8 @::ffff:10.53.0.8 a.example >dig.out.test$n 2>&1 || ret=1
|
||||
dig_with_opts @10.53.0.7 @::ffff:10.53.0.7 silent.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep -F ";; Skipping mapped address" dig.out.test$n >/dev/null || ret=1
|
||||
grep -F ";; No acceptable nameservers" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
import pytest
|
||||
|
||||
# isctest.asyncserver requires dnspython >= 2.0.0
|
||||
pytest.importorskip("dns", minversion="2.0.0")
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"delv.out.*",
|
||||
|
|
@ -20,7 +23,6 @@ pytestmark = pytest.mark.extra_artifacts(
|
|||
"nsupdate.out.*",
|
||||
"yamlget.out.*",
|
||||
"ans*/ans.run",
|
||||
"ans*/query.log",
|
||||
"ns*/anchor.*",
|
||||
"ns*/dsset-*",
|
||||
"ns*/keydata",
|
||||
|
|
|
|||
|
|
@ -429,10 +429,9 @@ class _ConnectionTeardownRequested(Exception):
|
|||
|
||||
|
||||
@dataclass
|
||||
class ResponseDropAndCloseConnection(ResponseAction):
|
||||
class CloseConnection(ResponseAction):
|
||||
"""
|
||||
Action which makes the server close the connection after the DNS query is
|
||||
received by the server (TCP only).
|
||||
Action which makes the server close the connection (TCP only).
|
||||
|
||||
The connection may be closed with a delay if requested.
|
||||
"""
|
||||
|
|
@ -555,8 +554,8 @@ class ConnectionReset(ConnectionHandler):
|
|||
make the server send an RST segment; this happens when the server closes a
|
||||
client's socket while there is still unread data in that socket's buffer.
|
||||
If closing the connection _after_ the query is read by the server is enough
|
||||
for a given use case, the ResponseDropAndCloseConnection response handler
|
||||
should be used instead.
|
||||
for a given use case, the CloseConnection response handler should be used
|
||||
instead.
|
||||
"""
|
||||
|
||||
delay: float = 0.0
|
||||
|
|
|
|||
Loading…
Reference in a new issue