Commit 87ed5e5efc for bind
commit 87ed5e5efce75fd75464b30aeb0e4d1cf8178f11
Author: Nicki Křížek <nicki@isc.org>
Date: Mon Sep 21 12:49:33 2026 +0000
Replace ditch.pl with isctest.tools.ditch
The query-burst tool used by fetchlimit and serve_stale becomes a
dnspython script with the same options. It was the only reason the
fetchlimit test required the Perl Net::DNS module, so that mark goes
with it.
Assisted-by: Claude:claude-fable-5-1
diff --git a/bin/tests/system/ditch.pl b/bin/tests/system/ditch.pl
deleted file mode 100644
index f77d02224d..0000000000
--- a/bin/tests/system/ditch.pl
+++ /dev/null
@@ -1,94 +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 tool for sending queries via UDP to specified address and
-# port, then exiting without waiting for a response.
-#
-# Usage: ditch.pl [-s <address>] [-p <port>] [filename]
-#
-# Input (in filename, if specified, otherwise stdin) is a series of one
-# or more DNS names and types to send as queries, e.g.:
-#
-# www.example.com A
-# www.example.org MX
-#
-# If not specified, address defaults to 127.0.0.1, port to 53.
-
-require 5.006.001;
-
-use strict;
-use Getopt::Std;
-use Net::DNS;
-use Net::DNS::Packet;
-use IO::File;
-use IO::Socket;
-
-sub usage {
- print ("Usage: ditch.pl [-s address] [-p port] [-b source_port] [file]\n");
- exit 1;
-}
-
-my %options={};
-getopts("s:p:b:", \%options);
-
-my $addr = "127.0.0.1";
-$addr = $options{s} if defined $options{s};
-
-my $port = 53;
-$port = $options{p} if defined $options{p};
-
-my $source_port = 0;
-$source_port = $options{b} if defined $options{b};
-
-my $file = "STDIN";
-if (@ARGV >= 1) {
- my $filename = shift @ARGV;
- open FH, "<$filename" or die "$filename: $!";
- $file = "FH";
-}
-
-my $input = "";
-while (defined(my $line = <$file>) ) {
- chomp $line;
- next if ($line =~ m/^ *#/);
- my @tokens = split (' ', $line);
-
- my $packet;
- if ($Net::DNS::VERSION > 0.68) {
- $packet = new Net::DNS::Packet();
- $@ and die $@;
- } else {
- my $err;
- ($packet, $err) = new Net::DNS::Packet();
- $err and die $err;
- }
-
- my $q = new Net::DNS::Question($tokens[0], $tokens[1], "IN");
- $packet->header->rd(1);
- $packet->push(question => $q);
-
- my $sock = IO::Socket::INET->new(
- PeerAddr => $addr,
- PeerPort => $port,
- Proto => "udp",
- LocalPort => $source_port,
- ) or die "$!";
-
- my $bytes = $sock->send($packet->data);
- #print ("sent $bytes bytes to $addr:$port:\n");
- #print (" ", unpack("H* ", $packet->data), "\n");
-
- $sock->close;
-}
-
-close $file;
diff --git a/bin/tests/system/fetchlimit/tests.sh b/bin/tests/system/fetchlimit/tests.sh
index 9ca4b70df7..03c456c6bc 100644
--- a/bin/tests/system/fetchlimit/tests.sh
+++ b/bin/tests/system/fetchlimit/tests.sh
@@ -46,7 +46,7 @@ burst() {
echo "${num}${2}${3}.lamesub.example A" >>burst.input.$$
fi
done
- $PERL ../ditch.pl -p ${PORT} -s ${server} -b ${EXTRAPORT8} burst.input.$$
+ $PYTHON -m isctest.tools.ditch -p ${PORT} -s ${server} -b ${EXTRAPORT8} burst.input.$$
rm -f burst.input.$$
}
diff --git a/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py b/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py
index 3ff7552d8d..1c68ed714e 100644
--- a/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py
+++ b/bin/tests/system/fetchlimit/tests_sh_fetchlimit.py
@@ -11,9 +11,7 @@
import pytest
-import isctest.mark
-
-EXTRA_ARTIFACTS = pytest.mark.extra_artifacts(
+pytestmark = pytest.mark.extra_artifacts(
[
"dig.out.*",
"wait_for_message.*",
@@ -24,11 +22,6 @@ EXTRA_ARTIFACTS = pytest.mark.extra_artifacts(
]
)
-pytestmark = [
- isctest.mark.requires_net_dns,
- EXTRA_ARTIFACTS,
-]
-
def test_fetchlimit(run_tests_sh):
run_tests_sh()
diff --git a/bin/tests/system/isctest/tools/ditch.py b/bin/tests/system/isctest/tools/ditch.py
new file mode 100644
index 0000000000..cec223121a
--- /dev/null
+++ b/bin/tests/system/isctest/tools/ditch.py
@@ -0,0 +1,84 @@
+# 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.
+
+"""
+Send DNS queries over UDP without waiting for the replies.
+
+Read "name type" lines from a file or stdin and fire one query per
+line at the server, all from the same source port; the replies are
+never read. This is how a test bursts a resolver with queries, e.g.
+to drive it into its fetch limits.
+"""
+
+from collections.abc import Iterable
+
+import argparse
+import fileinput
+import socket
+
+import dns.inet
+import dns.message
+
+
+def send_queries(
+ lines: Iterable[str], address: str, port: int, source_port: int = 0
+) -> int:
+ """
+ Send one recursive query per "name type" line to address:port over
+ UDP without reading any replies. Blank lines and lines starting
+ with "#" are skipped. Return the number of queries sent.
+ """
+ family = dns.inet.af_for_address(address)
+ sent = 0
+ with socket.socket(family, socket.SOCK_DGRAM) as sock:
+ sock.bind(("", source_port))
+ for line in lines:
+ fields = line.split()
+ if not fields or fields[0].startswith("#"):
+ continue
+ name, rdtype = fields[:2]
+ query = dns.message.make_query(name, rdtype)
+ sock.sendto(query.to_wire(), (address, port))
+ sent += 1
+ return sent
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(prog="ditch", description=__doc__)
+ parser.add_argument(
+ "-s",
+ "--server",
+ default="127.0.0.1",
+ help="server address (default: %(default)s)",
+ )
+ parser.add_argument(
+ "-p", "--port", type=int, default=53, help="server port (default: %(default)s)"
+ )
+ parser.add_argument(
+ "-b",
+ "--source-port",
+ type=int,
+ default=0,
+ help="source port to send from (default: any)",
+ )
+ parser.add_argument(
+ "file",
+ nargs="?",
+ default="-",
+ help="file with one 'name type' query per line (default: stdin)",
+ )
+ args = parser.parse_args()
+ with fileinput.input(files=args.file, encoding="utf-8") as lines:
+ send_queries(lines, args.server, args.port, args.source_port)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/bin/tests/system/serve_stale/tests.sh b/bin/tests/system/serve_stale/tests.sh
index d349744503..9606c41b3e 100755
--- a/bin/tests/system/serve_stale/tests.sh
+++ b/bin/tests/system/serve_stale/tests.sh
@@ -2599,7 +2599,7 @@ burst() {
num=$((num - 1))
echo "fetch${num}.example A" >>burst.input.$$
done
- $PERL ../ditch.pl -p ${PORT} -s 10.53.0.3 -b ${EXTRAPORT8} burst.input.$$
+ $PYTHON -m isctest.tools.ditch -p ${PORT} -s 10.53.0.3 -b ${EXTRAPORT8} burst.input.$$
rm -f burst.input.$$
}