]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dns: improved handling of corrupt additionals
authorPhilippe Antoine <pantoine@oisf.net>
Tue, 10 Sep 2024 13:31:00 +0000 (15:31 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 10 Jan 2025 08:16:34 +0000 (09:16 +0100)
Ticket: 7228

That means log the rest of queries and answers, even if the
final field additionals is corrupt.
Set an event in this case.

rules/dns-events.rules
rust/src/dns/dns.rs
rust/src/dns/parser.rs

index a3cf982c1e9ac9f49113daafd9057a59be877c32..815d941982cfeb651992a3d47ee1039634ce6157 100644 (file)
@@ -17,3 +17,6 @@ alert dns any any -> any any (msg:"SURICATA DNS Infinite loop"; app-layer-event:
 
 # Suricata's maximum number of DNS name labels was reached while parsing a resource name.
 alert dns any any -> any any (msg:"SURICATA DNS Too many labels"; app-layer-event:dns.too_many_labels; classtype:protocol-command-decode; sid:224010; rev:1;)
+
+alert dns any any -> any any (msg:"SURICATA DNS invalid additionals"; app-layer-event:dns.invalid_additionals; classtype:protocol-command-decode; sid:2240011; rev:1;)
+alert dns any any -> any any (msg:"SURICATA DNS invalid authorities"; app-layer-event:dns.invalid_authorities; classtype:protocol-command-decode; sid:2240012; rev:1;)
index 1dad2a94d99e32b6961d5a8add2fc0161048270d..b96956ba0a812e022894740f862eab7afca416e2 100644 (file)
@@ -135,6 +135,8 @@ pub enum DNSEvent {
     InfiniteLoop,
     /// Too many labels were found.
     TooManyLabels,
+    InvalidAdditionals,
+    InvalidAuthorities,
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -256,7 +258,9 @@ pub struct DNSMessage {
     pub queries: Vec<DNSQueryEntry>,
     pub answers: Vec<DNSAnswerEntry>,
     pub authorities: Vec<DNSAnswerEntry>,
+    pub invalid_authorities: bool,
     pub additionals: Vec<DNSAnswerEntry>,
+    pub invalid_additionals: bool,
 }
 
 #[derive(Debug, Default)]
@@ -399,6 +403,12 @@ pub(crate) fn dns_parse_request(input: &[u8]) -> Result<DNSTransaction, DNSParse
             let opcode = ((request.header.flags >> 11) & 0xf) as u8;
 
             let mut tx = DNSTransaction::new(Direction::ToServer);
+            if request.invalid_additionals {
+                tx.set_event(DNSEvent::InvalidAdditionals);
+            }
+            if request.invalid_authorities {
+                tx.set_event(DNSEvent::InvalidAuthorities);
+            }
             tx.request = Some(request);
 
             if z_flag {
@@ -452,6 +462,12 @@ pub(crate) fn dns_parse_response(input: &[u8]) -> Result<DNSTransaction, DNSPars
             let flags = response.header.flags;
 
             let mut tx = DNSTransaction::new(Direction::ToClient);
+            if response.invalid_additionals {
+                tx.set_event(DNSEvent::InvalidAdditionals);
+            }
+            if response.invalid_authorities {
+                tx.set_event(DNSEvent::InvalidAuthorities);
+            }
             tx.response = Some(response);
 
             if flags & 0x8000 == 0 {
@@ -1601,7 +1617,7 @@ mod tests {
     fn test_dns_event_from_id() {
         assert_eq!(DNSEvent::from_id(0), Some(DNSEvent::MalformedData));
         assert_eq!(DNSEvent::from_id(3), Some(DNSEvent::ZFlagSet));
-        assert_eq!(DNSEvent::from_id(9), None);
+        assert_eq!(DNSEvent::from_id(99), None);
     }
 
     #[test]
index 13864749aa93b416fc72c6c4bd8cef3915ee2908..d94daf98040210de574410748e9caddda62ab02c 100644 (file)
@@ -461,17 +461,40 @@ pub fn dns_parse_body<'a>(
         header.questions as usize,
     )(i)?;
     let (i, answers) = dns_parse_answer(i, message, header.answer_rr as usize, &mut flags)?;
-    let (i, authorities) = dns_parse_answer(i, message, header.authority_rr as usize, &mut flags)?;
-    let (i, additionals) = dns_parse_answer(i, message, header.additional_rr as usize, &mut flags)?;
+
+    let mut invalid_authorities = false;
+    let mut authorities = Vec::new();
+    let mut i_next = i;
+    let authorities_parsed = dns_parse_answer(i, message, header.authority_rr as usize, &mut flags);
+    if let Ok((i, authorities_ok)) = authorities_parsed {
+        authorities = authorities_ok;
+        i_next = i;
+    } else {
+        invalid_authorities = true;
+    }
+
+    let mut invalid_additionals = false;
+    let mut additionals = Vec::new();
+    if !invalid_authorities {
+        let additionals_parsed = dns_parse_answer(i_next, message, header.additional_rr as usize, &mut flags);
+        if let Ok((i, additionals_ok)) = additionals_parsed {
+                additionals = additionals_ok;
+                i_next = i;
+            } else {
+                invalid_additionals = true;
+            }
+    }
     Ok((
-        i,
+        i_next,
         (
             DNSMessage {
                 header,
                 queries,
                 answers,
                 authorities,
+                invalid_authorities,
                 additionals,
+                invalid_additionals,
             },
             flags,
         ),