]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Validate DNS message CLASS early in request processing
authorOndřej Surý <ondrej@isc.org>
Wed, 4 Mar 2026 09:46:58 +0000 (10:46 +0100)
committerEvan Hunt <each@isc.org>
Wed, 6 May 2026 04:05:37 +0000 (21:05 -0700)
Reject requests with unsupported or misused CLASS values before
further processing.  Only IN, CH, HS, RESERVED0 (for DNS Cookies),
ANY (for TKEY negotiation), and NONE (for DNS UPDATE) are accepted;
all other classes return NOTIMP.  Misuse of NONE or ANY outside
their allowed contexts returns FORMERR.

This adds further protection against bugs of the same general class
as YWH-PGM40640-70 and YWH-PGM40640-73.

(cherry picked from commit d41865a458b9ecd76be4097ac1bea1005cad72db)
(cherry picked from commit 1c8016c91c3674929f87cbe7ad09f3670e05ad4e)

bin/tests/system/unknown/tests.sh
lib/ns/client.c

index b14548a039c90f0fac00a7b67aa14e9506ee87db..092ae2d308afdd00281a9e38b347d9e06927a3ac 100644 (file)
@@ -75,8 +75,8 @@ n=$((n + 1))
 echo_i "querying for various representations of a CLASS10 TYPE1 record ($n)"
 for i in 1 2; do
   ret=0
-  $DIG +short $DIGOPTS @10.53.0.1 a$i.example a class10 >dig.out.$i.test$n || ret=1
-  echo '\# 4 0A000001' | $DIFF - dig.out.$i.test$n || ret=1
+  $DIG $DIGOPTS @10.53.0.1 a$i.example a class10 >dig.out.$i.test$n || ret=1
+  grep -q "NOTIMP" dig.out.$i.test$n || ret=1
   if [ $ret != 0 ]; then
     echo_i "#$i failed"
   fi
@@ -87,8 +87,8 @@ n=$((n + 1))
 echo_i "querying for various representations of a CLASS10 TXT record ($n)"
 for i in 1 2 3 4; do
   ret=0
-  $DIG +short $DIGOPTS @10.53.0.1 txt$i.example txt class10 >dig.out.$i.test$n || ret=1
-  echo '"hello"' | $DIFF - dig.out.$i.test$n || ret=1
+  $DIG $DIGOPTS @10.53.0.1 txt$i.example txt class10 >dig.out.$i.test$n || ret=1
+  grep -q "NOTIMP" dig.out.$i.test$n || ret=1
   if [ $ret != 0 ]; then
     echo_i "#$i failed"
   fi
@@ -99,8 +99,8 @@ n=$((n + 1))
 echo_i "querying for various representations of a CLASS10 TYPE123 record ($n)"
 for i in 1 2; do
   ret=0
-  $DIG +short $DIGOPTS @10.53.0.1 unk$i.example type123 class10 >dig.out.$i.test$n || ret=1
-  echo '\# 1 00' | $DIFF - dig.out.$i.test$n || ret=1
+  $DIG $DIGOPTS @10.53.0.1 unk$i.example type123 class10 >dig.out.$i.test$n || ret=1
+  grep -q "NOTIMP" dig.out.$i.test$n || ret=1
   if [ $ret != 0 ]; then
     echo_i "#$i failed"
   fi
index fed6a57176c3d1b3ea20f2a73761026c6fcfbb83..cbc8a0483624f6f60116e3b86a039f6d2c9d7348 100644 (file)
@@ -43,6 +43,7 @@
 #include <dns/dispatch.h>
 #include <dns/dnstap.h>
 #include <dns/edns.h>
+#include <dns/enumclass.h>
 #include <dns/events.h>
 #include <dns/message.h>
 #include <dns/peer.h>
@@ -1945,7 +1946,9 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
                }
        }
 
-       if (client->message->rdclass == 0) {
+       char classbuf[DNS_RDATACLASS_FORMATSIZE];
+       switch (client->message->rdclass) {
+       case dns_rdataclass_reserved0:
                if ((client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0 &&
                    client->message->opcode == dns_opcode_query &&
                    client->message->counts[DNS_SECTION_QUESTION] == 0U)
@@ -1966,12 +1969,49 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
                        return;
                }
 
+               ns_client_dumpmessage(client,
+                                     "message class could not be determined");
+               ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
+               isc_task_unpause(client->task);
+               return;
+       case dns_rdataclass_in:
+               break;
+       case dns_rdataclass_chaos:
+               break;
+       case dns_rdataclass_hs:
+               break;
+       case dns_rdataclass_none:
+               if (client->message->opcode != dns_opcode_update) {
+                       ns_client_dumpmessage(client,
+                                             "message class NONE can be only "
+                                             "used in DNS updates");
+                       ns_client_error(client, DNS_R_FORMERR);
+                       isc_task_unpause(client->task);
+                       return;
+               }
+               break;
+       case dns_rdataclass_any:
+               /*
+                * Required for TKEY negotiation.
+                */
+               if (client->message->tkey == 0) {
+                       ns_client_dumpmessage(client,
+                                             "message class ANY can be only "
+                                             "used for TKEY negotiation");
+                       ns_client_error(client, DNS_R_FORMERR);
+                       isc_task_unpause(client->task);
+                       return;
+               }
+               break;
+       default:
+               dns_rdataclass_format(client->message->rdclass, classbuf,
+                                     sizeof(classbuf));
+               ns_client_dumpmessage(client, NULL);
                ns_client_log(client, NS_LOGCATEGORY_CLIENT,
                              NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
-                             "message class could not be determined");
-               ns_client_dumpmessage(client, "message class could not be "
-                                             "determined");
-               ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
+                             "invalid message class: %s", classbuf);
+
+               ns_client_error(client, DNS_R_NOTIMP);
                isc_task_unpause(client->task);
                return;
        }
@@ -2010,7 +2050,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
                ns_client_log(client, NS_LOGCATEGORY_CLIENT,
                              NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
                              "no matching view in class '%s'", classname);
-               ns_client_dumpmessage(client, "no matching view in class");
+               ns_client_dumpmessage(client, NULL);
                ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
                isc_task_unpause(client->task);
                return;
@@ -2762,7 +2802,7 @@ ns_client_dumpmessage(ns_client_t *client, const char *reason) {
        int len = 1024;
        isc_result_t result;
 
-       if (!isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
+       if (!isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1)) || reason == NULL) {
                return;
        }