@ -20,6 +20,7 @@ use crate::core::{self, *};
use crate ::dcerpc ::parser ;
use crate ::dcerpc ::parser ;
use crate ::direction ::{ Direction , DIR_BOTH } ;
use crate ::direction ::{ Direction , DIR_BOTH } ;
use crate ::flow ::Flow ;
use crate ::flow ::Flow ;
use crate ::frames ::* ;
use nom7 ::error ::{ Error , ErrorKind } ;
use nom7 ::error ::{ Error , ErrorKind } ;
use nom7 ::number ::Endianness ;
use nom7 ::number ::Endianness ;
use nom7 ::{ Err , IResult , Needed } ;
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 ;
pub static mut ALPROTO_DCERPC : AppProto = ALPROTO_UNKNOWN ;
#[ derive(AppLayerFrameType) ]
pub enum DCERPCFrameType {
Pdu ,
Hdr ,
Data ,
}
pub fn dcerpc_type_string ( t : u8 ) -> String {
pub fn dcerpc_type_string ( t : u8 ) -> String {
match t {
match t {
DCERPC_TYPE_REQUEST = > "REQUEST" ,
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 mut parsed = 0 ;
let retval ;
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
// 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 ) {
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 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
// Check if header data was complete. In case of EoF or incomplete data, wait for more
// data else return error
// data else return error
if self . header . is_none ( ) & & ! cur_i . is_empty ( ) {
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 ) ;
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 ) ;
let current_call_id = self . get_hdr_call_id ( ) . unwrap_or ( 0 ) ;
match self . get_hdr_type ( ) {
match self . get_hdr_type ( ) {
@ -1063,7 +1080,7 @@ pub unsafe extern "C" fn rs_dcerpc_parse_request(
}
}
if ! stream_slice . is_gap ( ) {
if ! stream_slice . is_gap ( ) {
state . flow = Some ( flow ) ;
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 ( )
AppLayerResult ::err ( )
}
}
@ -1086,7 +1103,7 @@ pub unsafe extern "C" fn rs_dcerpc_parse_response(
}
}
if ! stream_slice . is_gap ( ) {
if ! stream_slice . is_gap ( ) {
state . flow = Some ( flow ) ;
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 ( )
AppLayerResult ::err ( )
}
}
@ -1263,8 +1280,8 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() {
get_state_data : rs_dcerpc_get_state_data ,
get_state_data : rs_dcerpc_get_state_data ,
apply_tx_config : None ,
apply_tx_config : None ,
flags : APP_LAYER_PARSER_OPT_ACCEPT_GAPS ,
flags : APP_LAYER_PARSER_OPT_ACCEPT_GAPS ,
get_frame_id_by_name : None ,
get_frame_id_by_name : Some( DCERPCFrameType ::ffi_id_from_name ) ,
get_frame_name_by_id : None ,
get_frame_name_by_id : Some( DCERPCFrameType ::ffi_name_from_id ) ,
} ;
} ;
let ip_proto_str = CString ::new ( "tcp" ) . unwrap ( ) ;
let ip_proto_str = CString ::new ( "tcp" ) . unwrap ( ) ;
@ -1301,7 +1318,8 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() {
#[ cfg(test) ]
#[ cfg(test) ]
mod tests {
mod tests {
use crate ::applayer ::AppLayerResult ;
use crate ::applayer ::{ AppLayerResult , StreamSlice } ;
use crate ::core ::* ;
use crate ::dcerpc ::dcerpc ::DCERPCState ;
use crate ::dcerpc ::dcerpc ::DCERPCState ;
use crate ::direction ::Direction ;
use crate ::direction ::Direction ;
use std ::cmp ;
use std ::cmp ;
@ -1729,7 +1747,7 @@ mod tests {
let mut dcerpc_state = DCERPCState ::new ( ) ;
let mut dcerpc_state = DCERPCState ::new ( ) ;
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( hdr ) = dcerpc_state . header {
assert_eq! ( 0 , hdr . hdrtype ) ;
assert_eq! ( 0 , hdr . hdrtype ) ;
@ -1765,11 +1783,11 @@ mod tests {
let mut dcerpc_state = DCERPCState ::new ( ) ;
let mut dcerpc_state = DCERPCState ::new ( ) ;
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) , // TODO ASK if this is correct?
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( ref bind ) = dcerpc_state . bind {
let bind_uuid = & bind . uuid_list [ 0 ] . uuid ;
let bind_uuid = & bind . uuid_list [ 0 ] . uuid ;
@ -1826,7 +1844,7 @@ mod tests {
let mut dcerpc_state = DCERPCState ::new ( ) ;
let mut dcerpc_state = DCERPCState ::new ( ) ;
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 ( ) ;
let mut dcerpc_state = DCERPCState ::new ( ) ;
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( ref back ) = dcerpc_state . bindack {
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
@ -2109,11 +2127,11 @@ mod tests {
}
}
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( ref back ) = dcerpc_state . bindack {
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
@ -2122,11 +2140,11 @@ mod tests {
}
}
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( ref back ) = dcerpc_state . bindack {
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
@ -2178,11 +2196,11 @@ mod tests {
] ;
] ;
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( ref back ) = dcerpc_state . bindack {
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
@ -2191,11 +2209,11 @@ mod tests {
}
}
assert_eq! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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! (
assert_eq! (
AppLayerResult ::ok ( ) ,
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 {
if let Some ( ref back ) = dcerpc_state . bindack {
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;
assert_eq! ( 1 , back . accepted_uuid_list . len ( ) ) ;