]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
rust/ldap: handle GAPs 11616/head
authorGiuseppe Longo <giuseppe@glongo.it>
Tue, 6 Aug 2024 18:39:46 +0000 (20:39 +0200)
committerVictor Julien <victor@inliniac.net>
Wed, 7 Aug 2024 17:04:35 +0000 (19:04 +0200)
Following the same logic as for PGSQL, if there is a gap in an LDAP request or
response, the parser tries to sync up again by checking if the message can be
parsed and effectively parses it on the next call.

Ticket #7176

rust/src/ldap/ldap.rs

index 14f3ee5e744f25da3fd800b05463ef638328916f..4c9c3947d7a81c77f8e8a772d74da5646de9a5a4 100644 (file)
@@ -90,6 +90,8 @@ pub struct LdapState {
     tx_index_completed: usize,
     request_frame: Option<Frame>,
     response_frame: Option<Frame>,
+    request_gap: bool,
+    response_gap: bool,
 }
 
 impl State<LdapTransaction> for LdapState {
@@ -111,6 +113,8 @@ impl LdapState {
             tx_index_completed: 0,
             request_frame: None,
             response_frame: None,
+            request_gap: false,
+            response_gap: false,
         }
     }
 
@@ -178,6 +182,22 @@ impl LdapState {
             return AppLayerResult::ok();
         }
 
+        if self.request_gap {
+            match ldap_parse_msg(input) {
+                Ok((_, msg)) => {
+                    let ldap_msg = LdapMessage::from(msg);
+                    if ldap_msg.is_unknown() {
+                        return AppLayerResult::err();
+                    }
+                    AppLayerResult::ok();
+                }
+                Err(_e) => {
+                    return AppLayerResult::err();
+                }
+            }
+            self.request_gap = false;
+        }
+
         let mut start = input;
         while !start.is_empty() {
             if self.request_frame.is_none() {
@@ -223,6 +243,22 @@ impl LdapState {
             return AppLayerResult::ok();
         }
 
+        if self.response_gap {
+            match ldap_parse_msg(input) {
+                Ok((_, msg)) => {
+                    let ldap_msg = LdapMessage::from(msg);
+                    if ldap_msg.is_unknown() {
+                        return AppLayerResult::err();
+                    }
+                    AppLayerResult::ok();
+                }
+                Err(_e) => {
+                    return AppLayerResult::err();
+                }
+            }
+            self.response_gap = false;
+        }
+
         let mut start = input;
         while !start.is_empty() {
             if self.response_frame.is_none() {
@@ -398,6 +434,14 @@ impl LdapState {
             self.response_frame = None;
         }
     }
+
+    fn on_request_gap(&mut self, _size: u32) {
+        self.request_gap = true;
+    }
+
+    fn on_response_gap(&mut self, _size: u32) {
+        self.response_gap = true;
+    }
 }
 
 fn tx_is_complete(op: &ProtocolOp, dir: Direction) -> bool {
@@ -490,7 +534,13 @@ unsafe extern "C" fn SCLdapParseRequest(
         }
     }
     let state = cast_pointer!(state, LdapState);
-    state.parse_request(flow, stream_slice)
+
+    if stream_slice.is_gap() {
+        state.on_request_gap(stream_slice.gap_size());
+    } else {
+        return state.parse_request(flow, stream_slice);
+    }
+    AppLayerResult::ok()
 }
 
 #[no_mangle]
@@ -506,7 +556,12 @@ unsafe extern "C" fn SCLdapParseResponse(
         }
     }
     let state = cast_pointer!(state, LdapState);
-    state.parse_response(flow, stream_slice)
+    if stream_slice.is_gap() {
+        state.on_response_gap(stream_slice.gap_size());
+    } else {
+        return state.parse_response(flow, stream_slice);
+    }
+    AppLayerResult::ok()
 }
 
 #[no_mangle]