diff --git a/rust/src/dcerpc/dcerpc.rs b/rust/src/dcerpc/dcerpc.rs index e247ab9eb954..a7b18b2be797 100644 --- a/rust/src/dcerpc/dcerpc.rs +++ b/rust/src/dcerpc/dcerpc.rs @@ -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());