]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Test server behavior when sending various UPDATE requests
authorEvan Hunt <each@isc.org>
Mon, 9 Mar 2026 04:50:04 +0000 (15:50 +1100)
committerMichał Kępień <michal@isc.org>
Thu, 7 May 2026 11:32:15 +0000 (13:32 +0200)
Send update messages for zones with CLASS0, ANY and NONE.  The class
ANY UPDATE also attempts to delete a KX record in an existing IN
class zone to trigger a REQUIRE.

Test that the server is still running.

bin/tests/system/class/tests_class_update.py
bin/tests/system/nsupdate/setup.sh
bin/tests/system/nsupdate/tests.sh
bin/tests/system/packet.pl

index e53bbc77ea6fa2f57e1b57364dfb5626a5dbe79e..30e3ba6d2ae80b017dabd075357958bbb28827e5 100644 (file)
@@ -12,7 +12,7 @@
 import socket
 import struct
 
-from dns import rdataclass, rdatatype, update
+from dns import message, rdataclass, rdatatype, update
 
 import pytest
 
@@ -35,6 +35,7 @@ def encode_name(name: str) -> bytes:
 @pytest.mark.parametrize(
     "rdtype,rdclass,ttl,rdata",
     [
+        (rdatatype.SRV, rdataclass.NONE, 0, b"\x00\x00\x00\x00\x00\x00\x01"),
         (rdatatype.SRV, rdataclass.NONE, 0, b"\x00"),
         (rdatatype.KX, rdataclass.NONE, 0, b""),
         (rdatatype.PX, rdataclass.NONE, 0, b""),
@@ -69,7 +70,7 @@ def test_class_invalid(rdtype, rdclass, ttl, rdata, named_port):
         s.sendall(packet)
         try:
             rwire = s.recv(4096)
-            res = dns.message.from_wire(rwire)
+            res = message.from_wire(rwire)
             isctest.check.formerr(res)
         except Exception:  # pylint: disable=broad-except
             pass
@@ -94,3 +95,43 @@ def test_class_chaosupdate(rdtype, rdata):
     up.add("foo.example.", 300, rdtype, rdata)
     res = isctest.query.tcp(up, "10.53.0.2")
     isctest.check.notimp(res)
+
+
+def test_class_undefined(ns2):
+    up = update.UpdateMessage(".", rdclass=257)
+    up.present(".", 0)
+    up.answer[0].rdclass = rdataclass.NONE
+    with ns2.watch_log_from_here() as watcher:
+        res = isctest.query.tcp(up, "10.53.0.2")
+        isctest.check.notimp(res)
+        watcher.wait_for_line("invalid message class: CLASS257")
+
+
+def test_class_zero(ns2):
+    up = update.UpdateMessage(".", rdclass=0)
+    up.present(".", 0)
+    up.answer[0].rdclass = rdataclass.NONE
+    with ns2.watch_log_from_here() as watcher:
+        res = isctest.query.tcp(up, "10.53.0.2")
+        isctest.check.formerr(res)
+        watcher.wait_for_line("message class could not be determined")
+
+
+def test_class_any(ns2):
+    up = update.UpdateMessage(".", rdclass=rdataclass.ANY)
+    up.present(".", 0)
+    up.answer[0].rdclass = rdataclass.NONE
+    with ns2.watch_log_from_here() as watcher:
+        res = isctest.query.tcp(up, "10.53.0.2")
+        isctest.check.formerr(res)
+        watcher.wait_for_line("message parsing failed: FORMERR")
+
+
+def test_class_none(ns2):
+    up = update.UpdateMessage(".", rdclass=rdataclass.NONE)
+    up.present(".", 0)
+    up.answer[0].rdclass = rdataclass.NONE
+    with ns2.watch_log_from_here() as watcher:
+        res = isctest.query.tcp(up, "10.53.0.2")
+        isctest.check.formerr(res)
+        watcher.wait_for_line("message parsing failed: FORMERR")
index 299330773a202246ee2b199d3f3576b1f3200339..9d27b20a760dfc92ccb5caa9237863d62c3496a7 100644 (file)
@@ -35,6 +35,7 @@ update.nil              IN SOA  ns1.example.nil. hostmaster.example.nil. (
                                 3600       ; minimum (1 hour)
                                 )
 update.nil.             NS      ns1.update.nil.
+update.nil.             KX      0 .
 ns1.update.nil.         A       10.53.0.2
 ns2.update.nil.                AAAA    ::1
 EOF
index 7a77faea6beefce4ee8d335bef9672f2b1352bda..d71136c563e780698cf68f3de484c0d7a80f29c4 100755 (executable)
@@ -485,8 +485,10 @@ grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
 n=$((n + 1))
 ret=0
 echo_i "check that TYPE=0 update is handled ($n)"
+nextpart ns1/named.run >/dev/null
 echo "a0e4280000010000000100000000060001c00c000000fe000000000000" \
-  | $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp >/dev/null || ret=1
+  | $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp -b >/dev/null || ret=1
+wait_for_log 2 "message parsing failed: FORMERR" ns1/named.run || ret=1
 $DIG $DIGOPTS +tcp version.bind txt ch @10.53.0.1 >dig.out.ns1.$n || ret=1
 grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
 [ $ret = 0 ] || {
@@ -497,20 +499,10 @@ grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
 n=$((n + 1))
 ret=0
 echo_i "check that TYPE=0 additional data is handled ($n)"
+nextpart ns1/named.run >/dev/null
 echo "a0e4280000010000000000010000060001c00c000000fe000000000000" \
-  | $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp >/dev/null || ret=1
-$DIG $DIGOPTS +tcp version.bind txt ch @10.53.0.1 >dig.out.ns1.$n || ret=1
-grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
-[ $ret = 0 ] || {
-  echo_i "failed"
-  status=1
-}
-
-n=$((n + 1))
-ret=0
-echo_i "check that update to undefined class is handled ($n)"
-echo "a0e4280000010001000000000000060101c00c000000fe000000000000" \
-  | $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp >/dev/null || ret=1
+  | $PERL ../packet.pl -a 10.53.0.1 -p ${PORT} -t tcp -b >/dev/null || ret=1
+wait_for_log 2 "message parsing failed: FORMERR" ns1/named.run || ret=1
 $DIG $DIGOPTS +tcp version.bind txt ch @10.53.0.1 >dig.out.ns1.$n || ret=1
 grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1
 [ $ret = 0 ] || {
index 900a0c071e622a74572b62e6be0d8d05896d79db..afb9f4784d73333cbf849a533d917d40dc3b5e0b 100644 (file)
@@ -40,6 +40,7 @@
 # -p <port>:     specify port
 # -t <protocol>: specify UDP or TCP
 # -r <num>:      send packet <num> times
+# -b:           blocking io
 # -d:            dump response packets
 #
 # If not specified, address defaults to 127.0.0.1, port to 53, protocol
@@ -51,6 +52,8 @@ use strict;
 use Getopt::Std;
 use IO::File;
 use IO::Socket;
+use Net::DNS;
+use Net::DNS::Packet;
 
 sub usage {
     print ("Usage: packet.pl [-a address] [-d] [-p port] [-t (tcp|udp)] [-r <repeats>] [file]\n");
@@ -61,8 +64,6 @@ my $sock;
 my $proto;
 
 sub dumppacket {
-    use Net::DNS;
-    use Net::DNS::Packet;
 
     my $rin;
     my $rout;
@@ -96,7 +97,7 @@ sub dumppacket {
 }
 
 my %options={};
-getopts("a:dp:t:r:", \%options);
+getopts("a:bdp:t:r:", \%options);
 
 my $addr = "127.0.0.1";
 $addr = $options{a} if defined $options{a};
@@ -111,6 +112,8 @@ usage if ($proto !~ /^(udp|tcp)$/);
 my $repeats = 1;
 $repeats = $options{r} if defined $options{r};
 
+my $blocking = defined $options{b} ? 1 : 0;
+
 my $file = "STDIN";
 if (@ARGV >= 1) {
     my $filename = shift @ARGV;
@@ -132,8 +135,22 @@ my $len = length $data;
 my $output = unpack("H*", $data);
 print ("sending $repeats time(s): $output\n");
 
+
+if (defined $options{d}) {
+    my $request;
+    if ($Net::DNS::VERSION > 0.68) {
+        $request = new Net::DNS::Packet(\$data, 0);
+        $@ and die $@;
+    } else {
+        my $err;
+        ($request, $err) = new Net::DNS::Packet(\$data, 0);
+        $err and die $err;
+    }
+    $request->print;
+}
+
 $sock = IO::Socket::INET->new(PeerAddr => $addr, PeerPort => $port,
-                                Blocking => 0,
+                                Blocking => $blocking,
                                 Proto => $proto,) or die "$!";
 
 STDOUT->autoflush(1);