]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dns: parse and alert on invalid opcodes
authorJason Ish <jason.ish@oisf.net>
Wed, 21 Dec 2022 01:17:38 +0000 (19:17 -0600)
committerVictor Julien <vjulien@oisf.net>
Tue, 24 Jan 2023 09:44:49 +0000 (10:44 +0100)
Accept DNS messages with an invalid opcode that are otherwise
valid. Such DNS message will create a parser event.

This is a change of behavior, previously an invalid opcode would cause
the DNS message to not be detected or parsed as DNS.

Issue: #5444

etc/schema.json
rules/dns-events.rules
rust/src/dns/dns.rs
rust/src/dns/log.rs

index 445f891da9907d06af2ffc24fd73fe9bf6d0137e..46a133f0321f9d2afd9a9ea653820602cc316e89 100644 (file)
                 "version": {
                     "type": "integer"
                 },
+                "opcode": {
+                    "description": "DNS opcode as an integer",
+                    "type": "integer"
+                },
                 "answers": {
                     "type": "array",
                     "minItems": 1,
                             },
                             "z": {
                                 "type": "boolean"
+                            },
+                            "opcode": {
+                                "description": "DNS opcode as an integer",
+                                "type": "integer"
                             }
                         },
                         "additionalProperties": false
                         },
                         "version": {
                             "type": "integer"
+                        },
+                        "opcode": {
+                            "description": "DNS opcode as an integer",
+                            "type": "integer"
                         }
                     },
                     "additionalProperties": false
index 0e34dae139d05d689520a349d7475f445f8a0384..d4c02b5c2f784ee1f63d852b28503b8200a74a39 100644 (file)
@@ -7,3 +7,4 @@ alert dns any any -> any any (msg:"SURICATA DNS Not a request"; flow:to_server;
 alert dns any any -> any any (msg:"SURICATA DNS Not a response"; flow:to_client; app-layer-event:dns.not_a_response; classtype:protocol-command-decode; sid:2240005; rev:2;)
 # Z flag (reserved) not 0
 alert dns any any -> any any (msg:"SURICATA DNS Z flag set"; app-layer-event:dns.z_flag_set; classtype:protocol-command-decode; sid:2240006; rev:2;)
+alert dns any any -> any any (msg:"SURICATA DNS Invalid opcode"; app-layer-event:dns.invalid_opcode; classtype:protocol-command-decode; sid:2240007; rev:1;)
index daeccade6b78404954fb3f46b8a640c8a20a0577..1e032b0467b676adc833382959bb5a14557e342d 100644 (file)
@@ -128,6 +128,7 @@ pub enum DNSEvent {
     NotRequest,
     NotResponse,
     ZFlagSet,
+    InvalidOpcode,
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -392,6 +393,7 @@ impl DNSState {
                 }
 
                 let z_flag = request.header.flags & 0x0040 != 0;
+                let opcode = ((request.header.flags >> 11) & 0xf) as u8;
 
                 let mut tx = self.new_tx();
                 tx.request = Some(request);
@@ -402,6 +404,10 @@ impl DNSState {
                     self.set_event(DNSEvent::ZFlagSet);
                 }
 
+                if opcode >= 7 {
+                    self.set_event(DNSEvent::InvalidOpcode);
+                }
+
                 return true;
             }
             Err(Err::Incomplete(_)) => {
@@ -454,6 +460,7 @@ impl DNSState {
                 }
 
                 let z_flag = response.header.flags & 0x0040 != 0;
+                let opcode = ((response.header.flags >> 11) & 0xf) as u8;
 
                 let mut tx = self.new_tx();
                 if let Some(ref mut config) = &mut self.config {
@@ -469,6 +476,10 @@ impl DNSState {
                     self.set_event(DNSEvent::ZFlagSet);
                 }
 
+                if opcode >= 7 {
+                    self.set_event(DNSEvent::InvalidOpcode);
+                }
+
                 return true;
             }
             Err(Err::Incomplete(_)) => {
@@ -629,11 +640,6 @@ impl DNSState {
 const DNS_HEADER_SIZE: usize = 12;
 
 fn probe_header_validity(header: DNSHeader, rlen: usize) -> (bool, bool, bool) {
-    let opcode = ((header.flags >> 11) & 0xf) as u8;
-    if opcode >= 7 {
-        //unassigned opcode
-        return (false, false, false);
-    }
     if 2 * (header.additional_rr as usize
         + header.answer_rr as usize
         + header.authority_rr as usize
index f0a3e7f620cad3723217b1b47269dd706d89a4a5..2fe3e7c37dbdb5c359fdb058051c7cb52bc08383 100644 (file)
@@ -506,6 +506,9 @@ fn dns_log_json_answer(
         js.set_bool("z", true)?;
     }
 
+    let opcode = ((header.flags >> 11) & 0xf) as u8;
+    js.set_uint("opcode", opcode as u64)?;
+
     if let Some(query) = response.queries.first() {
         js.set_string_from_bytes("rrname", &query.name)?;
         js.set_string("rrtype", &dns_rrtype_string(query.rrtype))?;
@@ -620,6 +623,8 @@ fn dns_log_query(
                 if request.header.flags & 0x0040 != 0 {
                     jb.set_bool("z", true)?;
                 }
+                let opcode = ((request.header.flags >> 11) & 0xf) as u8;
+                jb.set_uint("opcode", opcode as u64)?;
                 return Ok(true);
             }
         }