]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dcerpc/tcp: add frames support
authorShivani Bhardwaj <shivani@oisf.net>
Fri, 28 Jul 2023 05:43:54 +0000 (11:13 +0530)
committerVictor Julien <victor@inliniac.net>
Thu, 30 Jan 2025 09:52:05 +0000 (10:52 +0100)
Frames of the following types have been added for toserver direction:
1. Pdu: The entire Protocol Data Unit
2. Hdr: Header of the request
3. Data: PDU data

Feature 4904

rust/src/dcerpc/dcerpc.rs

index e247ab9eb954d632c132e8117cbe21e08c045da5..a7b18b2be797c0df6f0024dbab04df29c0947b68 100644 (file)
@@ -20,6 +20,7 @@ use crate::core::{self, *};
 use crate::dcerpc::parser;
 use crate::direction::{Direction, DIR_BOTH};
 use crate::flow::Flow;
+use crate::frames::*;
 use nom7::error::{Error, ErrorKind};
 use nom7::number::Endianness;
 use nom7::{Err, IResult, Needed};
@@ -117,6 +118,13 @@ pub(super) static mut DCERPC_MAX_TX: usize = 1024;
 
 pub static mut ALPROTO_DCERPC: AppProto = ALPROTO_UNKNOWN;
 
+#[derive(AppLayerFrameType)]
+pub enum DCERPCFrameType {
+    Pdu,
+    Hdr,
+    Data,
+}
+
 pub fn dcerpc_type_string(t: u8) -> String {
     match t {
         DCERPC_TYPE_REQUEST => "REQUEST",
@@ -873,10 +881,10 @@ impl DCERPCState {
         }
     }
 
-    pub fn handle_input_data(&mut self, input: &[u8], direction: Direction) -> AppLayerResult {
+    pub fn handle_input_data(&mut self, stream_slice: StreamSlice, direction: Direction) -> AppLayerResult {
         let mut parsed = 0;
         let retval;
-        let mut cur_i = input;
+        let mut cur_i = stream_slice.as_slice();
 
         // Skip the record since this means that its in the middle of a known length record
         if (self.ts_gap && direction == Direction::ToServer) || (self.tc_gap && direction == Direction::ToClient) {
@@ -910,6 +918,10 @@ impl DCERPCState {
         }
 
         let mut frag_bytes_consumed: u16 = 0;
+        let mut flow = std::ptr::null();
+        if let Some(f) = self.flow {
+            flow = f;
+        }
         // Check if header data was complete. In case of EoF or incomplete data, wait for more
         // data else return error
         if self.header.is_none() && !cur_i.is_empty() {
@@ -931,6 +943,11 @@ impl DCERPCState {
             return AppLayerResult::incomplete(parsed as u32, fraglen as u32 - parsed as u32);
         }
 
+        let _hdr = Frame::new(flow, &stream_slice, cur_i, parsed as i64, DCERPCFrameType::Hdr as u8, None);
+        let _pdu = Frame::new(flow, &stream_slice, cur_i, fraglen as i64, DCERPCFrameType::Pdu as u8, None);
+        if fraglen >= DCERPC_HDR_LEN && cur_i.len() > DCERPC_HDR_LEN as usize {
+            let _data = Frame::new(flow, &stream_slice, &cur_i[DCERPC_HDR_LEN as usize..], (fraglen - DCERPC_HDR_LEN) as i64, DCERPCFrameType::Data as u8, None);
+        }
         let current_call_id = self.get_hdr_call_id().unwrap_or(0);
 
         match self.get_hdr_type() {
@@ -1063,7 +1080,7 @@ pub unsafe extern "C" fn rs_dcerpc_parse_request(
     }
     if !stream_slice.is_gap() {
         state.flow = Some(flow);
-        return state.handle_input_data(stream_slice.as_slice(), Direction::ToServer);
+        return state.handle_input_data(stream_slice, Direction::ToServer);
     }
     AppLayerResult::err()
 }
@@ -1086,7 +1103,7 @@ pub unsafe extern "C" fn rs_dcerpc_parse_response(
     }
     if !stream_slice.is_gap() {
         state.flow = Some(flow);
-        return state.handle_input_data(stream_slice.as_slice(), Direction::ToClient);
+        return state.handle_input_data(stream_slice, Direction::ToClient);
     }
     AppLayerResult::err()
 }
@@ -1263,8 +1280,8 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() {
         get_state_data: rs_dcerpc_get_state_data,
         apply_tx_config: None,
         flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS,
-        get_frame_id_by_name: None,
-        get_frame_name_by_id: None,
+        get_frame_id_by_name: Some(DCERPCFrameType::ffi_id_from_name),
+        get_frame_name_by_id: Some(DCERPCFrameType::ffi_name_from_id),
     };
 
     let ip_proto_str = CString::new("tcp").unwrap();
@@ -1301,7 +1318,8 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() {
 
 #[cfg(test)]
 mod tests {
-    use crate::applayer::AppLayerResult;
+    use crate::applayer::{AppLayerResult, StreamSlice};
+    use crate::core::*;
     use crate::dcerpc::dcerpc::DCERPCState;
     use crate::direction::Direction;
     use std::cmp;
@@ -1729,7 +1747,7 @@ mod tests {
         let mut dcerpc_state = DCERPCState::new();
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(request, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(request, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(hdr) = dcerpc_state.header {
             assert_eq!(0, hdr.hdrtype);
@@ -1765,11 +1783,11 @@ mod tests {
         let mut dcerpc_state = DCERPCState::new();
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind1, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind1, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         assert_eq!(
             AppLayerResult::ok(), // TODO ASK if this is correct?
-            dcerpc_state.handle_input_data(bind2, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind2, STREAM_TOSERVER, 0), Direction::ToServer)
         );
     }
 
@@ -1792,7 +1810,7 @@ mod tests {
         ];
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bindbuf, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bindbuf, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(ref bind) = dcerpc_state.bind {
             let bind_uuid = &bind.uuid_list[0].uuid;
@@ -1826,7 +1844,7 @@ mod tests {
         let mut dcerpc_state = DCERPCState::new();
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bindbuf, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bindbuf, STREAM_TOSERVER, 0), Direction::ToServer)
         );
     }
 
@@ -1845,7 +1863,7 @@ mod tests {
         let mut dcerpc_state = DCERPCState::new();
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind_ack, Direction::ToClient)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack, STREAM_TOSERVER, 0), Direction::ToServer)
         );
     }
 
@@ -2096,11 +2114,11 @@ mod tests {
         ];
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind1, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind1, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind_ack1, Direction::ToClient)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack1, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(ref back) = dcerpc_state.bindack {
             assert_eq!(1, back.accepted_uuid_list.len());
@@ -2109,11 +2127,11 @@ mod tests {
         }
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind2, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind2, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind_ack2, Direction::ToClient)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack2, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(ref back) = dcerpc_state.bindack {
             assert_eq!(1, back.accepted_uuid_list.len());
@@ -2122,11 +2140,11 @@ mod tests {
         }
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind3, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind3, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind_ack3, Direction::ToClient)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind_ack3, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(ref back) = dcerpc_state.bindack {
             assert_eq!(1, back.accepted_uuid_list.len());
@@ -2178,11 +2196,11 @@ mod tests {
         ];
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bind, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bind, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(bindack, Direction::ToClient)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(bindack, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(ref back) = dcerpc_state.bindack {
             assert_eq!(1, back.accepted_uuid_list.len());
@@ -2191,11 +2209,11 @@ mod tests {
         }
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(alter_context, Direction::ToServer)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(alter_context, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         assert_eq!(
             AppLayerResult::ok(),
-            dcerpc_state.handle_input_data(alter_context_resp, Direction::ToClient)
+            dcerpc_state.handle_input_data(StreamSlice::from_slice(alter_context_resp, STREAM_TOSERVER, 0), Direction::ToServer)
         );
         if let Some(ref back) = dcerpc_state.bindack {
             assert_eq!(1, back.accepted_uuid_list.len());