diff --git a/rust/src/dcerpc/dcerpc.rs b/rust/src/dcerpc/dcerpc.rs new file mode 100644 index 0000000000..e414be15a1 --- /dev/null +++ b/rust/src/dcerpc/dcerpc.rs @@ -0,0 +1,2124 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use std::mem::transmute; + +use crate::applayer::AppLayerResult; +use crate::core; +use crate::dcerpc::parser; +use crate::log::*; +use nom::error::ErrorKind; +use nom::number::Endianness; +use std::cmp; + +// Constant DCERPC UDP Header length +pub const DCERPC_HDR_LEN: u16 = 16; +// FIRST flag set on the packet +pub const DCERPC_UUID_ENTRY_FLAG_FF: u16 = 0x0001; + +// Value to indicate first fragment +pub const PFC_FIRST_FRAG: u8 = 0x01; +// Value to indicate last fragment +pub const PFC_LAST_FRAG: u8 = 0x02; +// Cancel was pending at sender +pub const PFC_PENDING_CANCEL: u8 = 0x04; +pub const PFC_RESERVED_1: u8 = 0x08; +// supports concurrent multiplexing of a single connection. +pub const PFC_CONC_MPX: u8 = 0x10; +// only meaningful on `fault' packet; if true, guaranteed +// call did not execute. +pub const PFC_DID_NOT_EXECUTE: u8 = 0x20; +// `maybe' call semantics requested +pub const PFC_MAYBE: u8 = 0x40; +// if true, a non-nil object UUID was specified in the handle, and +// is present in the optional object field. If false, the object field +// is omitted. +pub const PFC_OBJECT_UUID: u8 = 0x80; + +pub const REASON_NOT_SPECIFIED: u8 = 0; +pub const TEMPORARY_CONGESTION: u8 = 1; +pub const LOCAL_LIMIT_EXCEEDED: u8 = 2; +pub const CALLED_PADDR_UNKNOWN: u8 = 3; /* not used */ +pub const PROTOCOL_VERSION_NOT_SUPPORTED: u8 = 4; +pub const DEFAULT_CONTEXT_NOT_SUPPORTED: u8 = 5; /* not used */ +pub const USER_DATA_NOT_READABLE: u8 = 6; /* not used */ +pub const NO_PSAP_AVAILABLE: u8 = 7; /* not used */ + +// DCERPC Header packet types +pub const DCERPC_TYPE_REQUEST: u8 = 0; +pub const DCERPC_TYPE_PING: u8 = 1; +pub const DCERPC_TYPE_RESPONSE: u8 = 2; +pub const DCERPC_TYPE_FAULT: u8 = 3; +pub const DCERPC_TYPE_WORKING: u8 = 4; +pub const DCERPC_TYPE_NOCALL: u8 = 5; +pub const DCERPC_TYPE_REJECT: u8 = 6; +pub const DCERPC_TYPE_ACK: u8 = 7; +pub const DCERPC_TYPE_CL_CANCEL: u8 = 8; +pub const DCERPC_TYPE_FACK: u8 = 9; +pub const DCERPC_TYPE_CANCEL_ACK: u8 = 10; +pub const DCERPC_TYPE_BIND: u8 = 11; +pub const DCERPC_TYPE_BINDACK: u8 = 12; +pub const DCERPC_TYPE_BINDNAK: u8 = 13; +pub const DCERPC_TYPE_ALTER_CONTEXT: u8 = 14; +pub const DCERPC_TYPE_ALTER_CONTEXT_RESP: u8 = 15; +pub const DCERPC_TYPE_AUTH3: u8 = 16; +pub const DCERPC_TYPE_SHUTDOWN: u8 = 17; +pub const DCERPC_TYPE_CO_CANCEL: u8 = 18; +pub const DCERPC_TYPE_ORPHANED: u8 = 19; +pub const DCERPC_TYPE_RTS: u8 = 20; + +pub fn dcerpc_type_string(t: u8) -> String { + match t { + DCERPC_TYPE_REQUEST => "REQUEST", + DCERPC_TYPE_PING => "PING", + DCERPC_TYPE_RESPONSE => "RESPONSE", + DCERPC_TYPE_FAULT => "FAULT", + DCERPC_TYPE_WORKING => "WORKING", + DCERPC_TYPE_NOCALL => "NOCALL", + DCERPC_TYPE_REJECT => "REJECT", + DCERPC_TYPE_ACK => "ACK", + DCERPC_TYPE_CL_CANCEL => "CL_CANCEL", + DCERPC_TYPE_FACK => "FACK", + DCERPC_TYPE_CANCEL_ACK => "CANCEL_ACK", + DCERPC_TYPE_BIND => "BIND", + DCERPC_TYPE_BINDACK => "BINDACK", + DCERPC_TYPE_BINDNAK => "BINDNAK", + DCERPC_TYPE_ALTER_CONTEXT => "ALTER_CONTEXT", + DCERPC_TYPE_ALTER_CONTEXT_RESP => "ALTER_CONTEXT_RESP", + DCERPC_TYPE_AUTH3 => "AUTH3", + DCERPC_TYPE_SHUTDOWN => "SHUTDOWN", + DCERPC_TYPE_CO_CANCEL => "CO_CANCEL", + DCERPC_TYPE_ORPHANED => "ORPHANED", + DCERPC_TYPE_RTS => "RTS", + _ => { + return (t).to_string(); + } + } + .to_string() +} + +#[derive(Debug)] +pub struct DCERPCRequest { + pub ctxid: u16, + pub opnum: u16, + pub first_request_seen: u8, + pub stub_data_buffer: Vec, + pub stub_data_buffer_len: u16, + pub stub_data_buffer_reset: bool, + pub cmd: u8, +} + +impl DCERPCRequest { + pub fn new() -> DCERPCRequest { + return DCERPCRequest { + ctxid: 0, + opnum: 0, + first_request_seen: 0, + stub_data_buffer: Vec::new(), + stub_data_buffer_len: 0, + stub_data_buffer_reset: false, + cmd: DCERPC_TYPE_REQUEST, + }; + } +} + +#[derive(Debug)] +pub struct DCERPCResponse { + pub stub_data_buffer: Vec, + pub stub_data_buffer_len: u16, + pub stub_data_buffer_reset: bool, + pub cmd: u8, +} + +impl DCERPCResponse { + pub fn new() -> DCERPCResponse { + return DCERPCResponse { + stub_data_buffer: Vec::new(), + stub_data_buffer_len: 0, + stub_data_buffer_reset: false, + cmd: DCERPC_TYPE_RESPONSE, + }; + } +} + +#[derive(Debug, Clone)] +pub struct DCERPCUuidEntry { + pub ctxid: u16, + pub internal_id: u16, + pub result: u16, + pub uuid: Vec, + pub version: u16, + pub versionminor: u16, + pub flags: u16, +} + +impl DCERPCUuidEntry { + pub fn new() -> DCERPCUuidEntry { + return DCERPCUuidEntry { + ctxid: 0, + internal_id: 0, + result: 0, + uuid: Vec::new(), + version: 0, + versionminor: 0, + flags: 0, + }; + } +} + +#[derive(Debug, PartialEq)] +pub struct Uuid { + pub time_low: Vec, + pub time_mid: Vec, + pub time_hi_and_version: Vec, + pub clock_seq_hi_and_reserved: u8, + pub clock_seq_low: u8, + pub node: Vec, +} + +#[derive(Debug)] +pub struct DCERPCHdr { + pub rpc_vers: u8, + pub rpc_vers_minor: u8, + pub hdrtype: u8, + pub pfc_flags: u8, + pub packed_drep: Vec, + pub frag_length: u16, + pub auth_length: u16, + pub call_id: u32, +} + +#[derive(Debug)] +pub struct DCERPCBind { + pub numctxitems: u8, + pub uuid_list: Vec, +} + +#[derive(Debug)] +pub struct BindCtxItem { + pub ctxid: u16, + pub uuid: Vec, + pub version: u16, + pub versionminor: u16, +} + +#[derive(Debug, PartialEq)] +pub struct DCERPCBindAckResult { + pub ack_result: u16, + pub ack_reason: u16, + pub transfer_syntax: Vec, + pub syntax_version: u32, +} + +#[derive(Debug)] +pub struct DCERPCBindAck { + pub accepted_uuid_list: Vec, + pub sec_addr_len: u16, + pub numctxitems: u8, + pub ctxitems: Vec, +} + +#[derive(Debug)] +pub struct DCERPCState { + pub header: Option, + pub bind: Option, + pub bindack: Option, + pub request: Option, + pub response: Option, + pub buffer_ts: Vec, + pub buffer_tc: Vec, + pub pad: u8, + pub padleft: u16, + pub bytes_consumed: u16, + pub tx_id: u16, + pub query_completed: bool, + pub data_needed_for_dir: u8, + pub prev_dir: u8, + pub detect_flags_ts: u64, + pub detect_flags_tc: u64, + pub de_state: Option<*mut core::DetectEngineState>, +} + +impl DCERPCState { + pub fn new() -> DCERPCState { + return DCERPCState { + header: None, + bind: None, + bindack: None, + request: None, + response: None, + buffer_ts: Vec::new(), + buffer_tc: Vec::new(), + pad: 0, + padleft: 0, + bytes_consumed: 0, + tx_id: 0, + query_completed: false, + data_needed_for_dir: core::STREAM_TOSERVER, + prev_dir: core::STREAM_TOSERVER, + detect_flags_ts: 0, + detect_flags_tc: 0, + de_state: None, + }; + } + + fn get_hdr_drep_0(&self) -> u8 { + if let Some(ref hdr) = &self.header { + return hdr.packed_drep[0]; + } + 0 + } + + fn get_endianness(&self) -> Endianness { + let drep_0 = self.get_hdr_drep_0(); + if drep_0 & 0x10 == 0 { + return Endianness::Big; + } + Endianness::Little + } + + fn get_hdr_fraglen(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = self.header { + return Some(hdr.frag_length); + } + // Shouldn't happen + None + } + + fn get_hdr_pfcflags(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = self.header { + return Some(hdr.pfc_flags); + } + // Shouldn't happen + None + } + + pub fn get_hdr_type(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = self.header { + return Some(hdr.hdrtype); + } + // Shouldn't happen + None + } + + pub fn get_hdr_rpc_vers(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = self.header { + return Some(hdr.rpc_vers); + } + // Shouldn't happen + None + } + + pub fn get_req_ctxid(&self) -> Option { + debug_validate_bug_on!(self.request.is_none()); + if let Some(ref req) = self.request { + return Some(req.ctxid); + } + // Shouldn't happen + None + } + + pub fn get_first_req_seen(&self) -> Option { + debug_validate_bug_on!(self.request.is_none()); + if let Some(ref req) = self.request { + return Some(req.first_request_seen); + } + // Shouldn't happen + None + } + + pub fn get_req_opnum(&self) -> Option { + debug_validate_bug_on!(self.request.is_none()); + if let Some(ref req) = self.request { + return Some(req.opnum); + } + // Shouldn't happen + None + } + + pub fn handle_gap_ts(&mut self) -> u8 { + if self.buffer_ts.len() > 0 { + self.buffer_ts.clear(); + } + return 0; + } + + pub fn handle_gap_tc(&mut self) -> u8 { + if self.buffer_tc.len() > 0 { + self.buffer_tc.clear(); + } + return 0; + } + + pub fn clean_buffer(&mut self, direction: u8) { + match direction { + core::STREAM_TOSERVER => { + self.buffer_ts.clear(); + } + _ => { + self.buffer_tc.clear(); + } + } + self.bytes_consumed = 0; + } + + pub fn extend_buffer(&mut self, buffer: &[u8], direction: u8) { + match direction { + core::STREAM_TOSERVER => { + self.buffer_ts.extend_from_slice(buffer); + } + _ => { + self.buffer_tc.extend_from_slice(buffer); + } + } + self.data_needed_for_dir = direction; + } + + pub fn reset_direction(&mut self, direction: u8) { + if direction == core::STREAM_TOSERVER { + self.data_needed_for_dir = core::STREAM_TOCLIENT; + } else { + self.data_needed_for_dir = core::STREAM_TOSERVER; + } + } + + /// Makes a call to the nom parser for parsing DCERPC Header. + /// + /// Arguments: + /// * `input`: + /// type: u8 vector slice. + /// description: bytes from the beginning of the buffer. + /// + /// Return value: + /// * Success: Number of bytes successfully parsed. + /// * Failure: -1 in case of Incomplete data or Eof. + /// -2 in case of Error while parsing. + pub fn process_header(&mut self, input: &[u8]) -> i32 { + match parser::parse_dcerpc_header(input) { + Ok((leftover_bytes, header)) => { + if header.rpc_vers != 5 + || (header.rpc_vers_minor != 0 && header.rpc_vers_minor != 1) + { + SCLogDebug!( + "DCERPC Header did not validate. Major version: {:?} Minor version: {:?}", + header.rpc_vers, + header.rpc_vers_minor + ); + return -1; + } + self.header = Some(header); + (input.len() - leftover_bytes.len()) as i32 + } + Err(nom::Err::Incomplete(_)) => { + // Insufficient data. + SCLogDebug!("Insufficient data while parsing DCERPC header"); + -1 + } + Err(nom::Err::Error(([], ErrorKind::Eof))) => { + SCLogDebug!("EoF reached while parsing DCERPC header"); + -1 + } + Err(_) => { + // Error, probably malformed data. + SCLogDebug!("An error occured while parsing DCERPC header"); + -2 + } + } + } + + pub fn handle_bindctxitem(&mut self, input: &[u8], uuid_internal_id: u16) -> i32 { + let endianness = self.get_endianness(); + match parser::parse_bindctx_item(input, endianness) { + Ok((leftover_bytes, ctxitem)) => { + let mut uuidentry = DCERPCUuidEntry::new(); + uuidentry.uuid = ctxitem.uuid; + uuidentry.internal_id = uuid_internal_id; + uuidentry.ctxid = ctxitem.ctxid; + uuidentry.version = ctxitem.version; + uuidentry.versionminor = ctxitem.versionminor; + let pfcflags = self.get_hdr_pfcflags().unwrap_or(0); + // Store the first frag flag in the uuid as pfc_flags will + // be overwritten by new packets + if pfcflags & PFC_FIRST_FRAG > 0 { + uuidentry.flags |= DCERPC_UUID_ENTRY_FLAG_FF; + } + if let Some(ref mut bind) = self.bind { + SCLogDebug!("DCERPC BIND CtxItem: Pushing uuid: {:?}", uuidentry); + bind.uuid_list.push(uuidentry); + } + (input.len() - leftover_bytes.len()) as i32 + } + Err(nom::Err::Incomplete(_)) => { + // Insufficient data. + SCLogDebug!("Insufficient data while parsing DCERPC BIND CTXItem"); + -1 + } + Err(_) => { + // Error, probably malformed data. + SCLogDebug!("An error occurred while parsing DCERPC BIND CTXItem"); + -1 + } + } + } + + pub fn process_bind_pdu(&mut self, input: &[u8]) -> i32 { + let mut retval = 0; + let mut idx = 12; // Bytes consumed if parser returns OK would be 12 + match parser::parse_dcerpc_bind(input) { + Ok((leftover_bytes, header)) => { + let numctxitems = header.numctxitems; + self.bind = Some(header); + for i in 0..numctxitems { + retval = self.handle_bindctxitem(&input[idx as usize..], i as u16); + if retval == -1 { + return -1; + } + idx = retval + idx; + } + // Bytes parsed with `parse_dcerpc_bind` + (bytes parsed per bindctxitem [44] * number + // of bindctxitems) + (input.len() - leftover_bytes.len()) as i32 + retval * numctxitems as i32 + } + Err(nom::Err::Incomplete(_)) => { + // Insufficient data. + SCLogDebug!("Insufficient data while parsing DCERPC BIND header"); + -1 + } + Err(_) => { + // Error, probably malformed data. + SCLogDebug!("An error occurred while parsing DCERPC BIND header"); + -1 + } + } + } + + pub fn process_bindack_pdu(&mut self, input: &[u8]) -> i32 { + match parser::parse_dcerpc_bindack(input) { + Ok((leftover_bytes, mut back)) => { + if let Some(ref mut bind) = self.bind { + let mut uuid_internal_id = 0; + for r in back.ctxitems.iter() { + for mut uuid in bind.uuid_list.iter_mut() { + if uuid.internal_id == uuid_internal_id { + uuid.result = r.ack_result; + if uuid.result != 0 { + break; + } + back.accepted_uuid_list.push(uuid.clone()); + SCLogDebug!("DCERPC BINDACK accepted UUID: {:?}", uuid); + } + } + uuid_internal_id += 1; + } + self.bindack = Some(back); + } + (input.len() - leftover_bytes.len()) as i32 + } + Err(nom::Err::Incomplete(_)) => { + // Insufficient data. + SCLogDebug!("Insufficient data while parsing DCERPC BINDACK"); + -1 + } + Err(_) => { + // Error, probably malformed data. + SCLogDebug!("An error occurred while parsing DCERPC BINDACK"); + -1 + } + } + } + + pub fn handle_stub_data(&mut self, input: &[u8], input_len: u16) -> u16 { + let mut retval: u16 = 0; + let hdrpfcflags = self.get_hdr_pfcflags().unwrap_or(0); + let padleft = self.padleft; + // Update the stub params based on the packet type + match self.get_hdr_type() { + Some(x) => match x { + DCERPC_TYPE_REQUEST => { + if let Some(ref mut req) = self.request { + retval = evaluate_stub_params( + input, + input_len, + hdrpfcflags, + padleft, + &mut req.stub_data_buffer, + &mut req.stub_data_buffer_len, + &mut req.stub_data_buffer_reset, + ); + } + } + DCERPC_TYPE_RESPONSE => { + if let Some(ref mut resp) = self.response { + retval = evaluate_stub_params( + input, + input_len, + hdrpfcflags, + padleft, + &mut resp.stub_data_buffer, + &mut resp.stub_data_buffer_len, + &mut resp.stub_data_buffer_reset, + ); + } + } + _ => { + SCLogDebug!("Unrecognized packet type"); + return 0; + } + }, + None => { + return 0; + } + } + // Update the remaining fragment length + self.padleft -= retval; + + retval + } + + /// Handles stub data for both request and response. + /// + /// Arguments: + /// * `input`: + /// type: u8 vector slice. + /// description: bytes left *after* parsing header. + /// * `bytes_consumed`: + /// type: 16 bit unsigned integer. + /// description: bytes consumed *after* parsing header. + /// * `dir`: + /// type: 8 bit unsigned integer. + /// description: direction whose stub is supposed to be handled. + /// + /// Return value: + /// * Success: Number of bytes successfully parsed. + /// * Failure: -1 in case fragment length defined by header mismatches the data. + pub fn handle_common_stub(&mut self, input: &[u8], bytes_consumed: u16, dir: u8) -> i32 { + let fraglen = self.get_hdr_fraglen().unwrap_or(0); + if fraglen < bytes_consumed as u16 + DCERPC_HDR_LEN { + return -1; + } + self.padleft = fraglen - DCERPC_HDR_LEN - bytes_consumed; + let mut input_left = input.len() as u16 - bytes_consumed; + let mut parsed = bytes_consumed; + while input_left > 0 && parsed < fraglen { + let retval = self.handle_stub_data(&input[parsed as usize..], input_left); + if retval > 0 && retval <= input_left { + parsed += retval; + input_left -= retval; + } else if input_left > 0 { + SCLogDebug!( + "Error parsing DCERPC {} stub data", + if dir == core::STREAM_TOSERVER { + "request" + } else { + "response" + } + ); + parsed -= input_left; + input_left = 0; + } + } + parsed as i32 + } + + pub fn process_request_pdu(&mut self, input: &[u8]) -> i32 { + let endianness = self.get_endianness(); + match parser::parse_dcerpc_request(input, endianness) { + Ok((leftover_input, mut request)) => { + request.cmd = self.get_hdr_type().unwrap_or(0); + self.request = Some(request); + let parsed = self.handle_common_stub( + &input, + (input.len() - leftover_input.len()) as u16, + core::STREAM_TOSERVER, + ); + parsed + } + Err(nom::Err::Incomplete(_)) => { + // Insufficient data. + SCLogDebug!("Insufficient data while parsing DCERPC REQUEST"); + -1 + } + Err(_) => { + // Error, probably malformed data. + SCLogDebug!("An error occurred while parsing DCERPC REQUEST"); + -1 + } + } + } + + pub fn handle_input_data(&mut self, input: &[u8], direction: u8) -> AppLayerResult { + let mut parsed; + let retval; + let input_len = input.len(); + let mut v: Vec; + // Set any query's completion status to false in the beginning + self.query_completed = false; + // Overwrite the dcerpc_state data in case of multiple complete queries in the + // same direction + if self.prev_dir == direction { + self.data_needed_for_dir = direction; + } + + let buffer = match direction { + core::STREAM_TOSERVER => { + if self.buffer_ts.len() + input_len > 1024 * 1024 { + SCLogDebug!("DCERPC TOSERVER stream: Buffer Overflow"); + return AppLayerResult::err(); + } + v = self.buffer_ts.split_off(0); + v.extend_from_slice(input); + v.as_slice() + } + _ => { + if self.buffer_tc.len() + input_len > 1024 * 1024 { + SCLogDebug!("DCERPC TOCLIENT stream: Buffer Overflow"); + return AppLayerResult::err(); + } + v = self.buffer_tc.split_off(0); + v.extend_from_slice(input); + v.as_slice() + } + }; + + if self.data_needed_for_dir != direction && buffer.len() != 0 { + return AppLayerResult::err(); + } + + // Set data_needed_for_dir in the same direction in case there is an issue with upcoming parsing + self.data_needed_for_dir = direction; + + // Check if header data was complete. In case of EoF or incomplete data, wait for more + // data else return error + if self.bytes_consumed < DCERPC_HDR_LEN && input_len > 0 { + parsed = self.process_header(&buffer); + if parsed == -1 { + self.extend_buffer(buffer, direction); + return AppLayerResult::ok(); + } + if parsed == -2 { + return AppLayerResult::err(); + } + self.bytes_consumed += parsed as u16; + } + + let fraglen = self.get_hdr_fraglen().unwrap_or(0); + + if (buffer.len() as u16) < fraglen { + SCLogDebug!("Possibly fragmented data, waiting for more.."); + self.extend_buffer(buffer, direction); + return AppLayerResult::ok(); + } else { + self.query_completed = true; + } + // TODO buffer extra data when input length is more than fraglen + parsed = self.bytes_consumed as i32; + + match self.get_hdr_type() { + Some(x) => match x { + DCERPC_TYPE_BIND | DCERPC_TYPE_ALTER_CONTEXT => { + retval = self.process_bind_pdu(&buffer[parsed as usize..]); + if retval == -1 { + return AppLayerResult::err(); + } + } + DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => { + retval = self.process_bindack_pdu(&buffer[parsed as usize..]); + if retval == -1 { + return AppLayerResult::err(); + } + } + DCERPC_TYPE_REQUEST => { + retval = self.process_request_pdu(&buffer[parsed as usize..]); + if retval == -1 { + return AppLayerResult::err(); + } + } + DCERPC_TYPE_RESPONSE => { + let mut response = DCERPCResponse::new(); + response.cmd = self.get_hdr_type().unwrap_or(DCERPC_TYPE_RESPONSE); + self.response = Some(response); + retval = self.handle_common_stub( + &buffer[parsed as usize..], + 0, + core::STREAM_TOCLIENT, + ); + if retval == -1 { + return AppLayerResult::err(); + } + self.tx_id += 1; // Complete response, maybe to be used in future? + } + _ => { + SCLogDebug!("Unrecognized packet type"); + self.clean_buffer(direction); + return AppLayerResult::err(); + } + }, + None => { + return AppLayerResult::err(); + } + } + self.bytes_consumed += retval as u16; + + // If the query has been completed, clean the buffer and reset the direction + if self.query_completed == true { + self.clean_buffer(direction); + self.reset_direction(direction); + } + self.prev_dir = direction; + return AppLayerResult::ok(); + } +} + +fn evaluate_stub_params( + input: &[u8], + input_len: u16, + hdrflags: u8, + lenleft: u16, + stub_data_buffer: &mut Vec, + stub_data_buffer_len: &mut u16, + stub_data_buffer_reset: &mut bool, +) -> u16 { + let stub_len: u16; + let fragtype = hdrflags & (PFC_FIRST_FRAG | PFC_LAST_FRAG); + stub_len = cmp::min(lenleft, input_len); + if stub_len == 0 { + return 0; + } + if stub_len == lenleft && (fragtype == 0 || (fragtype & PFC_LAST_FRAG > 0)) { + *stub_data_buffer_reset = true; + } + + let input_slice = &input[..stub_len as usize]; + stub_data_buffer.extend_from_slice(&input_slice); + *stub_data_buffer_len += stub_len; + + stub_len +} + +#[no_mangle] +pub extern "C" fn rs_parse_dcerpc_request_gap( + state: &mut DCERPCState, + _input_len: u32, +) -> AppLayerResult { + if state.handle_gap_ts() == 0 { + return AppLayerResult::ok(); + } + AppLayerResult::err() +} + +#[no_mangle] +pub extern "C" fn rs_parse_dcerpc_response_gap( + state: &mut DCERPCState, + _input_len: u32, +) -> AppLayerResult { + if state.handle_gap_tc() == 0 { + return AppLayerResult::ok(); + } + AppLayerResult::err() +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_parse_request( + _flow: *mut core::Flow, + state: &mut DCERPCState, + _pstate: *mut std::os::raw::c_void, + input: *const u8, + input_len: u32, + _data: *mut std::os::raw::c_void, + flags: u8, +) -> AppLayerResult { + if input_len > 0 && input != std::ptr::null_mut() { + let buf = build_slice!(input, input_len as usize); + return state.handle_input_data(buf, flags); + } + AppLayerResult::err() +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_parse_response( + _flow: *mut core::Flow, + state: &mut DCERPCState, + _pstate: *mut std::os::raw::c_void, + input: *const u8, + input_len: u32, + _data: *mut std::os::raw::c_void, + flags: u8, +) -> AppLayerResult { + if input_len > 0 { + if input != std::ptr::null_mut() { + let buf = build_slice!(input, input_len as usize); + return state.handle_input_data(buf, flags); + } + } + AppLayerResult::err() +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_state_new() -> *mut std::os::raw::c_void { + let state = DCERPCState::new(); + let boxed = Box::new(state); + transmute(boxed) +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_state_free(state: *mut std::os::raw::c_void) { + let _drop: Box = transmute(state); +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_state_transaction_free(_state: *mut std::os::raw::c_void, _tx_id: u64) { + // do nothing +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_get_tx_detect_state( + vtx: *mut std::os::raw::c_void, +) -> *mut core::DetectEngineState { + let dce_state = cast_pointer!(vtx, DCERPCState); + match dce_state.de_state { + Some(ds) => ds, + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_set_tx_detect_state( + vtx: *mut std::os::raw::c_void, + de_state: *mut core::DetectEngineState, +) -> u8 { + let dce_state = cast_pointer!(vtx, DCERPCState); + dce_state.de_state = Some(de_state); + 0 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_get_tx( + state: *mut std::os::raw::c_void, + _tx_id: u64, +) -> *mut DCERPCState { + let dce_state = cast_pointer!(state, DCERPCState); + dce_state +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_get_tx_cnt(_state: *mut std::os::raw::c_void) -> u8 { + 1 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_get_alstate_progress( + _tx: *mut std::os::raw::c_void, + _direction: u8, +) -> u8 { + 0 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_get_alstate_progress_completion_status(_direction: u8) -> u8 { + 1 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_get_tx_detect_flags(vtx: *mut std::os::raw::c_void, dir: u8) -> u64 { + let state = cast_pointer!(vtx, DCERPCState); + if dir & core::STREAM_TOSERVER != 0 { + return state.detect_flags_ts; + } + state.detect_flags_tc +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_set_tx_detect_flags( + vtx: *mut std::os::raw::c_void, + dir: u8, + flags: u64, +) { + let state = cast_pointer!(vtx, DCERPCState); + if dir & core::STREAM_TOSERVER != 0 { + state.detect_flags_ts = flags; + } else { + state.detect_flags_tc = flags; + } +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_get_stub_data( + state: &mut DCERPCState, + buf: *mut *const u8, + len: *mut u32, + endianness: *mut u8, + dir: u8, +) { + match dir { + core::STREAM_TOSERVER => { + if let Some(ref req) = state.request { + *len = req.stub_data_buffer_len as u32; + *buf = req.stub_data_buffer.as_ptr(); + SCLogDebug!("DCERPC Request stub buffer: Setting buffer to: {:?}", *buf); + } + } + _ => { + if let Some(ref resp) = state.response { + *len = resp.stub_data_buffer_len as u32; + *buf = resp.stub_data_buffer.as_ptr(); + SCLogDebug!("DCERPC Response stub buffer: Setting buffer to: {:?}", *buf); + } + } + } + *endianness = state.get_hdr_drep_0() & 0x10; +} + +#[cfg(test)] +mod tests { + use crate::applayer::AppLayerResult; + use crate::core; + use crate::dcerpc::dcerpc::DCERPCState; + use std::cmp; + + #[test] + fn test_process_header() { + let request: &[u8] = &[ + 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!(16, dcerpc_state.process_header(request)); + } + + #[test] + fn test_process_bind_pdu() { + let bind: &[u8] = &[ + 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f, 0xbf, 0x85, + 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x2c, 0x75, 0xce, 0x7e, 0x82, 0x3b, 0x06, 0xac, 0x1b, 0xf0, + 0xf5, 0xb7, 0xa7, 0xf7, 0x28, 0xaf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xe3, 0xb2, 0x10, 0xd1, 0xd0, 0x0c, 0xcc, 0x3d, + 0x2f, 0x80, 0x20, 0x7c, 0xef, 0xe7, 0x09, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xde, 0x85, 0x70, 0xc4, 0x02, 0x7c, + 0x60, 0x23, 0x67, 0x0c, 0x22, 0xbf, 0x18, 0x36, 0x79, 0x17, 0x01, 0x00, 0x02, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x41, 0x65, 0x29, 0x51, + 0xaa, 0xe7, 0x7b, 0xa8, 0xf2, 0x37, 0x0b, 0xd0, 0x3f, 0xb3, 0x36, 0xed, 0x05, 0x00, + 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x14, 0x96, + 0x80, 0x01, 0x2e, 0x78, 0xfb, 0x5d, 0xb4, 0x3c, 0x14, 0xb3, 0x3d, 0xaa, 0x02, 0xfb, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, + 0x3b, 0x04, 0x68, 0x3e, 0x63, 0xfe, 0x9f, 0xd8, 0x64, 0x55, 0xcd, 0xe7, 0x39, 0xaf, + 0x98, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x01, 0x00, 0x16, 0x7a, 0x4f, 0x1b, 0xdb, 0x25, 0x92, 0x55, 0xdd, 0xae, 0x9e, 0x5b, + 0x3e, 0x93, 0x66, 0x93, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x01, 0x00, 0xe8, 0xa4, 0x8a, 0xcf, 0x95, 0x6c, 0xc7, 0x8f, 0x14, 0xcc, + 0x56, 0xfc, 0x7b, 0x5f, 0x4f, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xd8, 0xda, 0xfb, 0xbc, 0xa2, 0x55, 0x6f, 0x5d, + 0xc0, 0x2d, 0x88, 0x6f, 0x00, 0x17, 0x52, 0x8d, 0x06, 0x00, 0x03, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x3f, 0x17, 0x55, 0x0c, 0xf4, 0x23, + 0x3c, 0xca, 0xe6, 0xa0, 0xaa, 0xcc, 0xb5, 0xe3, 0xf9, 0xce, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x6a, 0x28, 0x19, 0x39, + 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0xc9, 0x9f, + 0x3e, 0x6e, 0x82, 0x0a, 0x2b, 0x28, 0x37, 0x78, 0xe1, 0x13, 0x70, 0x05, 0x38, 0x4d, + 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x00, + 0x11, 0xaa, 0x4b, 0x15, 0xdf, 0xa6, 0x86, 0x3f, 0xfb, 0xe0, 0x09, 0xb7, 0xf8, 0x56, + 0xd2, 0x3f, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x01, 0x00, 0xee, 0x99, 0xc4, 0x25, 0x11, 0xe4, 0x95, 0x62, 0x29, 0xfa, 0xfd, 0x26, + 0x57, 0x02, 0xf1, 0xce, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x01, 0x00, 0xba, 0x81, 0x9e, 0x1a, 0xdf, 0x2b, 0xba, 0xe4, 0xd3, 0x17, + 0x41, 0x60, 0x6d, 0x2d, 0x9e, 0x28, 0x03, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0xa0, 0x24, 0x03, 0x9a, 0xa9, 0x99, 0xfb, 0xbe, + 0x49, 0x11, 0xad, 0x77, 0x30, 0xaa, 0xbc, 0xb6, 0x02, 0x00, 0x03, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x32, 0x04, 0x7e, 0xae, 0xec, 0x28, + 0xd1, 0x55, 0x83, 0x4e, 0xc3, 0x47, 0x5d, 0x1d, 0xc6, 0x65, 0x02, 0x00, 0x03, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0xc6, 0xa4, 0x81, 0x48, + 0x66, 0x2a, 0x74, 0x7d, 0x56, 0x6e, 0xc5, 0x1d, 0x19, 0xf2, 0xb5, 0xb6, 0x03, 0x00, + 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, 0xcb, 0xae, + 0xb3, 0xc0, 0x0c, 0xf4, 0xa4, 0x5e, 0x91, 0x72, 0xdd, 0x53, 0x24, 0x70, 0x89, 0x02, + 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, + 0xb8, 0xd0, 0xa0, 0x1a, 0x5e, 0x7a, 0x2d, 0xfe, 0x35, 0xc6, 0x7d, 0x08, 0x0d, 0x33, + 0x73, 0x18, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, + 0x01, 0x00, 0x21, 0xd3, 0xaa, 0x09, 0x03, 0xa7, 0x0b, 0xc2, 0x06, 0x45, 0xd9, 0x6c, + 0x75, 0xc2, 0x15, 0xa8, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x01, 0x00, 0xe1, 0xbd, 0x59, 0xfc, 0xbc, 0xa9, 0x95, 0xc2, 0x68, 0x79, + 0xf3, 0x75, 0xe0, 0xae, 0x6c, 0xe5, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x17, 0x00, 0x01, 0x00, 0x06, 0x52, 0xb4, 0x71, 0x70, 0x15, 0x4e, 0xf5, + 0x7f, 0x08, 0x86, 0x14, 0xe6, 0x17, 0xd5, 0x97, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!(1068, dcerpc_state.process_bind_pdu(bind)); + } + + #[test] + fn test_handle_bindctxitem() { + let bind: &[u8] = &[ + 0x00, 0x00, 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f, + 0xbf, 0x85, 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!(44, dcerpc_state.handle_bindctxitem(bind, 0)); + } + + #[test] + fn test_process_bindack_pdu() { + let bind: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f, + 0xbf, 0x85, 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x2c, 0x75, 0xce, 0x7e, 0x82, 0x3b, 0x06, 0xac, + 0x1b, 0xf0, 0xf5, 0xb7, 0xa7, 0xf7, 0x28, 0xaf, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xe3, 0xb2, 0x10, 0xd1, 0xd0, 0x0c, + 0xcc, 0x3d, 0x2f, 0x80, 0x20, 0x7c, 0xef, 0xe7, 0x09, 0xe0, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xde, 0x85, 0x70, 0xc4, + 0x02, 0x7c, 0x60, 0x23, 0x67, 0x0c, 0x22, 0xbf, 0x18, 0x36, 0x79, 0x17, 0x01, 0x00, + 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x41, 0x65, + 0x29, 0x51, 0xaa, 0xe7, 0x7b, 0xa8, 0xf2, 0x37, 0x0b, 0xd0, 0x3f, 0xb3, 0x36, 0xed, + 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, + 0x14, 0x96, 0x80, 0x01, 0x2e, 0x78, 0xfb, 0x5d, 0xb4, 0x3c, 0x14, 0xb3, 0x3d, 0xaa, + 0x02, 0xfb, 0x06, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x3b, 0x04, 0x68, 0x3e, 0x63, 0xfe, 0x9f, 0xd8, 0x64, 0x55, 0xcd, 0xe7, + 0x39, 0xaf, 0x98, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x00, 0x16, 0x7a, 0x4f, 0x1b, 0xdb, 0x25, 0x92, 0x55, 0xdd, 0xae, + 0x9e, 0x5b, 0x3e, 0x93, 0x66, 0x93, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0xe8, 0xa4, 0x8a, 0xcf, 0x95, 0x6c, 0xc7, 0x8f, + 0x14, 0xcc, 0x56, 0xfc, 0x7b, 0x5f, 0x4f, 0xe8, 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xd8, 0xda, 0xfb, 0xbc, 0xa2, 0x55, + 0x6f, 0x5d, 0xc0, 0x2d, 0x88, 0x6f, 0x00, 0x17, 0x52, 0x8d, 0x06, 0x00, 0x03, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x3f, 0x17, 0x55, 0x0c, + 0xf4, 0x23, 0x3c, 0xca, 0xe6, 0xa0, 0xaa, 0xcc, 0xb5, 0xe3, 0xf9, 0xce, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x6a, 0x28, + 0x19, 0x39, 0x0c, 0xb1, 0xd0, 0x11, 0x9b, 0xa8, 0x00, 0xc0, 0x4f, 0xd9, 0x2e, 0xf5, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, + 0xc9, 0x9f, 0x3e, 0x6e, 0x82, 0x0a, 0x2b, 0x28, 0x37, 0x78, 0xe1, 0x13, 0x70, 0x05, + 0x38, 0x4d, 0x01, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x01, 0x00, 0x11, 0xaa, 0x4b, 0x15, 0xdf, 0xa6, 0x86, 0x3f, 0xfb, 0xe0, 0x09, 0xb7, + 0xf8, 0x56, 0xd2, 0x3f, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x01, 0x00, 0xee, 0x99, 0xc4, 0x25, 0x11, 0xe4, 0x95, 0x62, 0x29, 0xfa, + 0xfd, 0x26, 0x57, 0x02, 0xf1, 0xce, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xba, 0x81, 0x9e, 0x1a, 0xdf, 0x2b, 0xba, 0xe4, + 0xd3, 0x17, 0x41, 0x60, 0x6d, 0x2d, 0x9e, 0x28, 0x03, 0x00, 0x03, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0xa0, 0x24, 0x03, 0x9a, 0xa9, 0x99, + 0xfb, 0xbe, 0x49, 0x11, 0xad, 0x77, 0x30, 0xaa, 0xbc, 0xb6, 0x02, 0x00, 0x03, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x32, 0x04, 0x7e, 0xae, + 0xec, 0x28, 0xd1, 0x55, 0x83, 0x4e, 0xc3, 0x47, 0x5d, 0x1d, 0xc6, 0x65, 0x02, 0x00, + 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00, 0xc6, 0xa4, + 0x81, 0x48, 0x66, 0x2a, 0x74, 0x7d, 0x56, 0x6e, 0xc5, 0x1d, 0x19, 0xf2, 0xb5, 0xb6, + 0x03, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x00, + 0xcb, 0xae, 0xb3, 0xc0, 0x0c, 0xf4, 0xa4, 0x5e, 0x91, 0x72, 0xdd, 0x53, 0x24, 0x70, + 0x89, 0x02, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, + 0x01, 0x00, 0xb8, 0xd0, 0xa0, 0x1a, 0x5e, 0x7a, 0x2d, 0xfe, 0x35, 0xc6, 0x7d, 0x08, + 0x0d, 0x33, 0x73, 0x18, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x01, 0x00, 0x21, 0xd3, 0xaa, 0x09, 0x03, 0xa7, 0x0b, 0xc2, 0x06, 0x45, + 0xd9, 0x6c, 0x75, 0xc2, 0x15, 0xa8, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0xe1, 0xbd, 0x59, 0xfc, 0xbc, 0xa9, 0x95, 0xc2, + 0x68, 0x79, 0xf3, 0x75, 0xe0, 0xae, 0x6c, 0xe5, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00, 0x06, 0x52, 0xb4, 0x71, 0x70, 0x15, + 0x4e, 0xf5, 0x7f, 0x08, 0x86, 0x14, 0xe6, 0x17, 0xd5, 0x97, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let bindack: &[u8] = &[ + 0xb8, 0x10, 0xb8, 0x10, 0xce, 0x47, 0x00, 0x00, 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, + 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, 0xf6, 0x6e, 0x18, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!(16, dcerpc_state.process_header(bind)); + assert_eq!(1068, dcerpc_state.process_bind_pdu(&bind[16..])); + assert_eq!(604, dcerpc_state.process_bindack_pdu(bindack)); + if let Some(back) = dcerpc_state.bindack { + assert_eq!(1, back.accepted_uuid_list.len()); + assert_eq!( + vec!(57, 25, 40, 106, 177, 12, 17, 208, 155, 168, 0, 192, 79, 217, 46, 245), + back.accepted_uuid_list[0].uuid + ); + assert_eq!(11, back.accepted_uuid_list[0].internal_id); + } + } + + #[test] + pub fn test_process_request_pdu() { + let request: &[u8] = &[ + 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x45, 0x00, 0x2c, 0x00, + 0x4d, 0x00, 0x73, 0x00, 0x53, 0x00, 0x59, 0x00, 0x2a, 0x00, 0x4a, 0x00, 0x7a, 0x00, + 0x3e, 0x00, 0x58, 0x00, 0x21, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x41, 0x00, 0x4b, 0x00, + 0x4b, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x24, 0x00, 0x38, 0x00, 0x54, 0x00, 0x60, 0x00, + 0x2d, 0x00, 0x29, 0x00, 0x64, 0x00, 0x5b, 0x00, 0x77, 0x00, 0x3a, 0x00, 0x4c, 0x00, + 0x24, 0x00, 0x23, 0x00, 0x66, 0x00, 0x43, 0x00, 0x68, 0x00, 0x22, 0x00, 0x55, 0x00, + 0x29, 0x00, 0x2c, 0x00, 0x4f, 0x00, 0x5a, 0x00, 0x50, 0x00, 0x61, 0x00, 0x2a, 0x00, + 0x6f, 0x00, 0x2f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x67, 0x00, + 0x68, 0x00, 0x68, 0x00, 0x49, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x53, 0x00, + 0x4c, 0x00, 0x25, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x64, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x24, 0x00, 0x46, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x45, 0x00, + 0x6f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x33, 0x00, 0x38, 0x00, 0x47, 0x00, 0x71, 0x00, + 0x5a, 0x00, 0x37, 0x00, 0x7a, 0x00, 0x35, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x26, 0x00, + 0x37, 0x00, 0x69, 0x00, 0x75, 0x00, 0x36, 0x00, 0x37, 0x00, 0x47, 0x00, 0x21, 0x00, + 0x2d, 0x00, 0x69, 0x00, 0x37, 0x00, 0x78, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x4b, 0x00, + 0x5c, 0x00, 0x74, 0x00, 0x3e, 0x00, 0x52, 0x00, 0x7a, 0x00, 0x49, 0x00, 0x31, 0x00, + 0x5a, 0x00, 0x7b, 0x00, 0x29, 0x00, 0x3b, 0x00, 0x78, 0x00, 0x3b, 0x00, 0x55, 0x00, + 0x3e, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x38, 0x00, + 0x2a, 0x00, 0x59, 0x00, 0x6b, 0x00, 0x42, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x6a, 0x00, + 0x49, 0x00, 0x2c, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x49, 0x00, + 0x55, 0x00, 0x35, 0x00, 0x61, 0x00, 0x72, 0x00, 0x77, 0x00, 0x38, 0x00, 0x32, 0x00, + 0x24, 0x00, 0x46, 0x00, 0x32, 0x00, 0x32, 0x00, 0x27, 0x00, 0x64, 0x00, 0x5a, 0x00, + 0x77, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x63, 0x00, + 0x4f, 0x00, 0x67, 0x00, 0x64, 0x00, 0x39, 0x00, 0x37, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x28, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x3e, 0x00, 0x59, 0x00, 0x28, 0x00, 0x67, 0x00, + 0x52, 0x00, 0x35, 0x00, 0x5a, 0x00, 0x7c, 0x00, 0x56, 0x00, 0x6a, 0x00, 0x5c, 0x00, + 0x3c, 0x00, 0x30, 0x00, 0x59, 0x00, 0x5c, 0x00, 0x5e, 0x00, 0x38, 0x00, 0x54, 0x00, + 0x5c, 0x00, 0x5b, 0x00, 0x42, 0x00, 0x62, 0x00, 0x70, 0x00, 0x34, 0x00, 0x5c, 0x00, + 0x57, 0x00, 0x7a, 0x00, 0x4b, 0x00, 0x2f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x4f, 0x00, + 0x41, 0x00, 0x33, 0x00, 0x52, 0x00, 0x36, 0x00, 0x27, 0x00, 0x30, 0x00, 0x6d, 0x00, + 0x4a, 0x00, 0x30, 0x00, 0x78, 0x00, 0x46, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x29, 0x00, + 0x66, 0x00, 0x3f, 0x00, 0x72, 0x00, 0x71, 0x00, 0x75, 0x00, 0x4c, 0x00, 0x2b, 0x00, + 0x5c, 0x00, 0x46, 0x00, 0x52, 0x00, 0x7b, 0x00, 0x5c, 0x00, 0x69, 0x00, 0x66, 0x00, + 0x56, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x72, 0x00, 0x61, 0x00, 0x68, 0x00, 0x28, 0x00, + 0x7d, 0x00, 0x58, 0x00, 0x2a, 0x00, 0x7b, 0x00, 0x28, 0x00, 0x5b, 0x00, 0x54, 0x00, + 0x3a, 0x00, 0x26, 0x00, 0x52, 0x00, 0x44, 0x00, 0x60, 0x00, 0x50, 0x00, 0x65, 0x00, + 0x48, 0x00, 0x7d, 0x00, 0x2a, 0x00, 0x74, 0x00, 0x49, 0x00, 0x7b, 0x00, 0x21, 0x00, + 0x61, 0x00, 0x52, 0x00, 0x43, 0x00, 0x5f, 0x00, 0x5a, 0x00, 0x74, 0x00, 0x5c, 0x00, + 0x62, 0x00, 0x68, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x2b, 0x00, 0x6f, 0x00, 0x7c, 0x00, + 0x42, 0x00, 0x67, 0x00, 0x32, 0x00, 0x58, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2f, 0x00, + 0x2d, 0x00, 0x60, 0x00, 0x62, 0x00, 0x51, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x31, 0x00, + 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x25, 0x00, 0x58, 0x00, 0x4a, 0x00, + 0x76, 0x00, 0x32, 0x00, 0x62, 0x00, 0x27, 0x00, 0x42, 0x00, 0x40, 0x00, 0x53, 0x00, + 0x7c, 0x00, 0x7d, 0x00, 0x50, 0x00, 0x3d, 0x00, 0x40, 0x00, 0x76, 0x00, 0x38, 0x00, + 0x58, 0x00, 0x39, 0x00, 0x63, 0x00, 0x3c, 0x00, 0x5b, 0x00, 0x23, 0x00, 0x53, 0x00, + 0x7a, 0x00, 0x54, 0x00, 0x74, 0x00, 0x61, 0x00, 0x76, 0x00, 0x4a, 0x00, 0x3e, 0x00, + 0x33, 0x00, 0x75, 0x00, 0x66, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x33, 0x00, 0x71, 0x00, + 0x76, 0x00, 0x48, 0x00, 0x71, 0x00, 0x41, 0x00, 0x6f, 0x00, 0x2a, 0x00, 0x67, 0x00, + 0x70, 0x00, 0x21, 0x00, 0x70, 0x00, 0x4b, 0x00, 0x52, 0x00, 0x58, 0x00, 0x68, 0x00, + 0x23, 0x00, 0x39, 0x00, 0x46, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x57, 0x00, 0x3a, 0x00, + 0x79, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x55, 0x00, 0x33, 0x00, 0x65, 0x00, 0x49, 0x00, + 0x72, 0x00, 0x30, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x4a, 0x00, + 0x60, 0x00, 0x79, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x58, 0x00, 0x75, 0x00, 0x44, 0x00, + 0x59, 0x00, 0x58, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x74, 0x00, 0x51, 0x00, + 0x57, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x23, 0x00, 0x45, 0x00, 0x60, 0x00, + 0x4c, 0x00, 0x72, 0x00, 0x4e, 0x00, 0x74, 0x00, 0x40, 0x00, 0x76, 0x00, 0x75, 0x00, + 0x74, 0x00, 0x56, 0x00, 0x44, 0x00, 0x29, 0x00, 0x62, 0x00, 0x58, 0x00, 0x31, 0x00, + 0x78, 0x00, 0x32, 0x00, 0x52, 0x00, 0x4a, 0x00, 0x6b, 0x00, 0x55, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x7d, 0x00, 0x68, 0x00, 0x3f, 0x00, + 0x28, 0x00, 0x21, 0x00, 0x53, 0x00, 0x48, 0x00, 0x5a, 0x00, 0x34, 0x00, 0x36, 0x00, + 0x35, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x69, 0x00, 0x23, 0x00, 0x75, 0x00, + 0x55, 0x00, 0x43, 0x00, 0x75, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x62, 0x00, 0x6f, 0x00, + 0x37, 0x00, 0x4e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x3c, 0x00, + 0x71, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x36, 0x00, 0x62, 0x00, 0x63, 0x00, + 0x53, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x61, 0x00, 0x4c, 0x00, 0x28, 0x00, 0x2b, 0x00, + 0x4c, 0x00, 0x4e, 0x00, 0x66, 0x00, 0x5f, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x75, 0x00, + 0x45, 0x00, 0x37, 0x00, 0x28, 0x00, 0x56, 0x00, 0x36, 0x00, 0x6a, 0x00, 0x3e, 0x00, + 0x64, 0x00, 0x34, 0x00, 0x6a, 0x00, 0x7d, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x7a, 0x00, + 0x3e, 0x00, 0x75, 0x00, 0x38, 0x00, 0x7b, 0x00, 0x42, 0x00, 0x76, 0x00, 0x29, 0x00, + 0x4c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x2b, 0x00, 0x51, 0x00, + 0x47, 0x00, 0x22, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x44, 0x00, 0x5d, 0x00, + 0x59, 0x00, 0x63, 0x00, 0x5c, 0x00, 0x24, 0x00, 0x35, 0x00, 0x34, 0x00, 0x70, 0x00, + 0x69, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!(16, dcerpc_state.process_header(&request)); + assert_eq!(1008, dcerpc_state.process_request_pdu(&request[16..])); + } + + #[test] + pub fn test_parse_dcerpc() { + let request: &[u8] = &[ + 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x45, 0x00, 0x2c, 0x00, + 0x4d, 0x00, 0x73, 0x00, 0x53, 0x00, 0x59, 0x00, 0x2a, 0x00, 0x4a, 0x00, 0x7a, 0x00, + 0x3e, 0x00, 0x58, 0x00, 0x21, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x41, 0x00, 0x4b, 0x00, + 0x4b, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x24, 0x00, 0x38, 0x00, 0x54, 0x00, 0x60, 0x00, + 0x2d, 0x00, 0x29, 0x00, 0x64, 0x00, 0x5b, 0x00, 0x77, 0x00, 0x3a, 0x00, 0x4c, 0x00, + 0x24, 0x00, 0x23, 0x00, 0x66, 0x00, 0x43, 0x00, 0x68, 0x00, 0x22, 0x00, 0x55, 0x00, + 0x29, 0x00, 0x2c, 0x00, 0x4f, 0x00, 0x5a, 0x00, 0x50, 0x00, 0x61, 0x00, 0x2a, 0x00, + 0x6f, 0x00, 0x2f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x67, 0x00, + 0x68, 0x00, 0x68, 0x00, 0x49, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x72, 0x00, 0x53, 0x00, + 0x4c, 0x00, 0x25, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x64, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x24, 0x00, 0x46, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x45, 0x00, + 0x6f, 0x00, 0x40, 0x00, 0x41, 0x00, 0x33, 0x00, 0x38, 0x00, 0x47, 0x00, 0x71, 0x00, + 0x5a, 0x00, 0x37, 0x00, 0x7a, 0x00, 0x35, 0x00, 0x6b, 0x00, 0x3c, 0x00, 0x26, 0x00, + 0x37, 0x00, 0x69, 0x00, 0x75, 0x00, 0x36, 0x00, 0x37, 0x00, 0x47, 0x00, 0x21, 0x00, + 0x2d, 0x00, 0x69, 0x00, 0x37, 0x00, 0x78, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x4b, 0x00, + 0x5c, 0x00, 0x74, 0x00, 0x3e, 0x00, 0x52, 0x00, 0x7a, 0x00, 0x49, 0x00, 0x31, 0x00, + 0x5a, 0x00, 0x7b, 0x00, 0x29, 0x00, 0x3b, 0x00, 0x78, 0x00, 0x3b, 0x00, 0x55, 0x00, + 0x3e, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x38, 0x00, + 0x2a, 0x00, 0x59, 0x00, 0x6b, 0x00, 0x42, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x6a, 0x00, + 0x49, 0x00, 0x2c, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x35, 0x00, 0x4f, 0x00, 0x49, 0x00, + 0x55, 0x00, 0x35, 0x00, 0x61, 0x00, 0x72, 0x00, 0x77, 0x00, 0x38, 0x00, 0x32, 0x00, + 0x24, 0x00, 0x46, 0x00, 0x32, 0x00, 0x32, 0x00, 0x27, 0x00, 0x64, 0x00, 0x5a, 0x00, + 0x77, 0x00, 0x2e, 0x00, 0x37, 0x00, 0x77, 0x00, 0x2e, 0x00, 0x28, 0x00, 0x63, 0x00, + 0x4f, 0x00, 0x67, 0x00, 0x64, 0x00, 0x39, 0x00, 0x37, 0x00, 0x31, 0x00, 0x30, 0x00, + 0x28, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x3e, 0x00, 0x59, 0x00, 0x28, 0x00, 0x67, 0x00, + 0x52, 0x00, 0x35, 0x00, 0x5a, 0x00, 0x7c, 0x00, 0x56, 0x00, 0x6a, 0x00, 0x5c, 0x00, + 0x3c, 0x00, 0x30, 0x00, 0x59, 0x00, 0x5c, 0x00, 0x5e, 0x00, 0x38, 0x00, 0x54, 0x00, + 0x5c, 0x00, 0x5b, 0x00, 0x42, 0x00, 0x62, 0x00, 0x70, 0x00, 0x34, 0x00, 0x5c, 0x00, + 0x57, 0x00, 0x7a, 0x00, 0x4b, 0x00, 0x2f, 0x00, 0x6b, 0x00, 0x6a, 0x00, 0x4f, 0x00, + 0x41, 0x00, 0x33, 0x00, 0x52, 0x00, 0x36, 0x00, 0x27, 0x00, 0x30, 0x00, 0x6d, 0x00, + 0x4a, 0x00, 0x30, 0x00, 0x78, 0x00, 0x46, 0x00, 0x65, 0x00, 0x4e, 0x00, 0x29, 0x00, + 0x66, 0x00, 0x3f, 0x00, 0x72, 0x00, 0x71, 0x00, 0x75, 0x00, 0x4c, 0x00, 0x2b, 0x00, + 0x5c, 0x00, 0x46, 0x00, 0x52, 0x00, 0x7b, 0x00, 0x5c, 0x00, 0x69, 0x00, 0x66, 0x00, + 0x56, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x72, 0x00, 0x61, 0x00, 0x68, 0x00, 0x28, 0x00, + 0x7d, 0x00, 0x58, 0x00, 0x2a, 0x00, 0x7b, 0x00, 0x28, 0x00, 0x5b, 0x00, 0x54, 0x00, + 0x3a, 0x00, 0x26, 0x00, 0x52, 0x00, 0x44, 0x00, 0x60, 0x00, 0x50, 0x00, 0x65, 0x00, + 0x48, 0x00, 0x7d, 0x00, 0x2a, 0x00, 0x74, 0x00, 0x49, 0x00, 0x7b, 0x00, 0x21, 0x00, + 0x61, 0x00, 0x52, 0x00, 0x43, 0x00, 0x5f, 0x00, 0x5a, 0x00, 0x74, 0x00, 0x5c, 0x00, + 0x62, 0x00, 0x68, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x2b, 0x00, 0x6f, 0x00, 0x7c, 0x00, + 0x42, 0x00, 0x67, 0x00, 0x32, 0x00, 0x58, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2f, 0x00, + 0x2d, 0x00, 0x60, 0x00, 0x62, 0x00, 0x51, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x31, 0x00, + 0x48, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x25, 0x00, 0x58, 0x00, 0x4a, 0x00, + 0x76, 0x00, 0x32, 0x00, 0x62, 0x00, 0x27, 0x00, 0x42, 0x00, 0x40, 0x00, 0x53, 0x00, + 0x7c, 0x00, 0x7d, 0x00, 0x50, 0x00, 0x3d, 0x00, 0x40, 0x00, 0x76, 0x00, 0x38, 0x00, + 0x58, 0x00, 0x39, 0x00, 0x63, 0x00, 0x3c, 0x00, 0x5b, 0x00, 0x23, 0x00, 0x53, 0x00, + 0x7a, 0x00, 0x54, 0x00, 0x74, 0x00, 0x61, 0x00, 0x76, 0x00, 0x4a, 0x00, 0x3e, 0x00, + 0x33, 0x00, 0x75, 0x00, 0x66, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x33, 0x00, 0x71, 0x00, + 0x76, 0x00, 0x48, 0x00, 0x71, 0x00, 0x41, 0x00, 0x6f, 0x00, 0x2a, 0x00, 0x67, 0x00, + 0x70, 0x00, 0x21, 0x00, 0x70, 0x00, 0x4b, 0x00, 0x52, 0x00, 0x58, 0x00, 0x68, 0x00, + 0x23, 0x00, 0x39, 0x00, 0x46, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x57, 0x00, 0x3a, 0x00, + 0x79, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x55, 0x00, 0x33, 0x00, 0x65, 0x00, 0x49, 0x00, + 0x72, 0x00, 0x30, 0x00, 0x4f, 0x00, 0x41, 0x00, 0x6e, 0x00, 0x31, 0x00, 0x4a, 0x00, + 0x60, 0x00, 0x79, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x58, 0x00, 0x75, 0x00, 0x44, 0x00, + 0x59, 0x00, 0x58, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x74, 0x00, 0x51, 0x00, + 0x57, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x23, 0x00, 0x45, 0x00, 0x60, 0x00, + 0x4c, 0x00, 0x72, 0x00, 0x4e, 0x00, 0x74, 0x00, 0x40, 0x00, 0x76, 0x00, 0x75, 0x00, + 0x74, 0x00, 0x56, 0x00, 0x44, 0x00, 0x29, 0x00, 0x62, 0x00, 0x58, 0x00, 0x31, 0x00, + 0x78, 0x00, 0x32, 0x00, 0x52, 0x00, 0x4a, 0x00, 0x6b, 0x00, 0x55, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x6f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x7d, 0x00, 0x68, 0x00, 0x3f, 0x00, + 0x28, 0x00, 0x21, 0x00, 0x53, 0x00, 0x48, 0x00, 0x5a, 0x00, 0x34, 0x00, 0x36, 0x00, + 0x35, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x75, 0x00, 0x69, 0x00, 0x23, 0x00, 0x75, 0x00, + 0x55, 0x00, 0x43, 0x00, 0x75, 0x00, 0x2f, 0x00, 0x73, 0x00, 0x62, 0x00, 0x6f, 0x00, + 0x37, 0x00, 0x4e, 0x00, 0x25, 0x00, 0x25, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x3c, 0x00, + 0x71, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x36, 0x00, 0x62, 0x00, 0x63, 0x00, + 0x53, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x61, 0x00, 0x4c, 0x00, 0x28, 0x00, 0x2b, 0x00, + 0x4c, 0x00, 0x4e, 0x00, 0x66, 0x00, 0x5f, 0x00, 0x4b, 0x00, 0x43, 0x00, 0x75, 0x00, + 0x45, 0x00, 0x37, 0x00, 0x28, 0x00, 0x56, 0x00, 0x36, 0x00, 0x6a, 0x00, 0x3e, 0x00, + 0x64, 0x00, 0x34, 0x00, 0x6a, 0x00, 0x7d, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x7a, 0x00, + 0x3e, 0x00, 0x75, 0x00, 0x38, 0x00, 0x7b, 0x00, 0x42, 0x00, 0x76, 0x00, 0x29, 0x00, + 0x4c, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x2b, 0x00, 0x51, 0x00, + 0x47, 0x00, 0x22, 0x00, 0x48, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x44, 0x00, 0x5d, 0x00, + 0x59, 0x00, 0x63, 0x00, 0x5c, 0x00, 0x24, 0x00, 0x35, 0x00, 0x34, 0x00, 0x70, 0x00, + 0x69, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request, core::STREAM_TOSERVER) + ); + if let Some(hdr) = dcerpc_state.header { + assert_eq!(0, hdr.hdrtype); + assert_eq!(5, hdr.rpc_vers); + assert_eq!(1024, hdr.frag_length); + } + if let Some(req) = dcerpc_state.request { + assert_eq!(11, req.ctxid); + assert_eq!(9, req.opnum); + assert_eq!(1, req.first_request_seen); + assert_eq!(1000, req.stub_data_buffer_len); + assert_eq!(true, req.stub_data_buffer_reset); + } + } + + #[test] + pub fn test_parse_bind_pdu() { + let bind1: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x01, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, + 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let bind2: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x02, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, + 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x67, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), // TODO ASK if this is correct? + dcerpc_state.handle_input_data(&bind2, core::STREAM_TOSERVER) + ); + } + + #[test] + pub fn test_parse_bind_frag_1() { + let bind1: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0xc7, 0x70, 0x0d, 0x3e, 0x71, 0x37, 0x39, 0x0d, 0x3a, 0x4f, + 0xd3, 0xdc, 0xca, 0x49, 0xe8, 0xa3, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x84, 0xb6, 0x55, 0x75, 0xdb, 0x9e, 0xba, 0x54, + 0x56, 0xd3, 0x45, 0x10, 0xb7, 0x7a, 0x2a, 0xe2, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x6e, 0x39, 0x21, 0x24, 0x70, 0x6f, + 0x41, 0x57, 0x54, 0x70, 0xb8, 0xc3, 0x5e, 0x89, 0x3b, 0x43, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x39, 0x6a, 0x86, 0x5d, + 0x24, 0x0f, 0xd2, 0xf7, 0xb6, 0xce, 0x95, 0x9c, 0x54, 0x1d, 0x3a, 0xdb, 0x02, 0x00, + 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x12, 0xa5, + 0xdd, 0xc5, 0x55, 0xce, 0xc3, 0x46, 0xbd, 0xa0, 0x94, 0x39, 0x3c, 0x0d, 0x9b, 0x5b, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, + 0x87, 0x1c, 0x8b, 0x6e, 0x11, 0xa8, 0x67, 0x98, 0xd4, 0x5d, 0xf6, 0x8a, 0x2f, 0x33, + 0x24, 0x7b, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x9b, 0x82, 0x13, 0xd1, 0x28, 0xe0, 0x63, 0xf3, 0x62, 0xee, 0x76, 0x73, + 0xf9, 0xac, 0x3d, 0x2e, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x00, 0xa9, 0xd4, 0x73, 0xf2, 0xed, 0xad, 0xe8, 0x82, 0xf8, 0xcf, + 0x9d, 0x9f, 0x66, 0xe6, 0x43, 0x37, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x06, 0x2b, 0x85, 0x38, 0x4f, 0x73, 0x96, 0xb1, + 0x73, 0xe1, 0x59, 0xbe, 0x9d, 0xe2, 0x6c, 0x07, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + ]; + let bind2: &[u8] = &[ + 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xbf, 0xfa, 0xbb, 0xa4, 0x9e, 0x5c, + 0x80, 0x61, 0xb5, 0x8b, 0x79, 0x69, 0xa6, 0x32, 0x88, 0x77, 0x01, 0x00, 0x01, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x39, 0xa8, 0x2c, 0x39, + 0x73, 0x50, 0x06, 0x8d, 0xf2, 0x37, 0x1e, 0x1e, 0xa8, 0x8f, 0x46, 0x98, 0x02, 0x00, + 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x91, 0x13, + 0xd0, 0xa7, 0xef, 0xc4, 0xa7, 0x96, 0x0c, 0x4a, 0x0d, 0x29, 0x80, 0xd3, 0xfe, 0xbf, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, + 0xcc, 0x2b, 0x55, 0x1d, 0xd4, 0xa4, 0x0d, 0xfb, 0xcb, 0x6f, 0x86, 0x36, 0xa6, 0x57, + 0xc3, 0x21, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x01, 0x00, 0x43, 0x7b, 0x07, 0xee, 0x85, 0xa8, 0xb9, 0x3a, 0x0f, 0xf9, 0x83, 0x70, + 0xe6, 0x0b, 0x4f, 0x33, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x01, 0x00, 0x9c, 0x6a, 0x15, 0x8c, 0xd6, 0x9c, 0xa6, 0xc3, 0xb2, 0x9e, + 0x62, 0x9f, 0x3d, 0x8e, 0x47, 0x73, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, + 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind2, core::STREAM_TOSERVER) + ); + if let Some(ref bind) = dcerpc_state.bind { + assert_eq!(16, bind.numctxitems); + assert_eq!(0, dcerpc_state.bytes_consumed); // because the buffer is cleared after a query is complete + } + } + + #[test] + pub fn test_parse_bind_frag_2() { + let request1: &[u8] = &[ + 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ]; + let request2: &[u8] = &[0x0D, 0x0E]; + let request3: &[u8] = &[0x0F, 0x10, 0x11, 0x12, 0x13, 0x14]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request2, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request3, core::STREAM_TOSERVER) + ); + if let Some(ref req) = dcerpc_state.request { + assert_eq!(20, req.stub_data_buffer_len); + } + } + + #[test] + pub fn test_parse_bind_frag_3() { + let request1: &[u8] = &[ + 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request1, core::STREAM_TOSERVER) + ); + } + + #[test] + pub fn test_parse_bind_frag_4() { + let request1: &[u8] = &[ + 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request1, core::STREAM_TOSERVER) + ); + } + + #[test] + pub fn test_parse_dcerpc_frag_1() { + let fault: &[u8] = &[ + 0x05, 0x00, 0x03, 0x03, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xf7, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + let request1: &[u8] = &[0x05, 0x00]; + let request2: &[u8] = &[ + 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::err(), + dcerpc_state.handle_input_data(&fault, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request2, core::STREAM_TOSERVER) + ); + if let Some(ref req) = dcerpc_state.request { + assert_eq!(12, req.stub_data_buffer_len); + } + } + + #[test] + pub fn test_parse_dcerpc_frag_2() { + let request1: &[u8] = &[ + 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ]; + let request2: &[u8] = &[0x05, 0x00]; + let request3: &[u8] = &[ + 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request2, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&request3, core::STREAM_TOSERVER) + ); + } + + #[test] + pub fn test_parse_dcerpc_back_frag() { + let bind_ack1: &[u8] = &[ + 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x48, 0x1a, 0x00, 0x00, + ]; + let bind_ack2: &[u8] = &[ + 0x0c, 0x00, 0x5c, 0x50, 0x49, 0x50, 0x45, 0x5c, 0x6c, 0x73, 0x61, 0x73, 0x73, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + dcerpc_state.data_needed_for_dir = core::STREAM_TOCLIENT; + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind_ack1, core::STREAM_TOCLIENT) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind_ack2, core::STREAM_TOCLIENT) + ); + } + + #[test] + // Check if the parser accepts bind pdus that have context ids starting + // from a non-zero value. + pub fn test_parse_bind_pdu_ctx_id_non_zero() { + let bindbuf: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + let expected_uuid: &[u8] = &[ + 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x46, + ]; + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bindbuf, core::STREAM_TOSERVER) + ); + if let Some(ref bind) = dcerpc_state.bind { + let bind_uuid = &bind.uuid_list[0].uuid; + assert_eq!(1, bind.uuid_list.len()); + assert_eq!( + cmp::Ordering::Equal, + bind_uuid + .iter() + .zip(expected_uuid) + .map(|(x, y)| x.cmp(y)) + .find(|&ord| ord != cmp::Ordering::Equal) + .unwrap_or(bind_uuid.len().cmp(&expected_uuid.len())) + ); + } + } + + #[test] + // Check for endless loop with bind PDUs (Imported from C code) + pub fn test_parse_bind_pdu_infinite_loop() { + let bindbuf: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x01, 0x02, 0x03, 0x04, 0xFF, /* ka boom - endless loop */ + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bindbuf, core::STREAM_TOSERVER) + ); + } + + #[test] + // Check for endless loop with bind_ack PDUs (Imported from C code) + pub fn test_parse_bindack_pdu_infinite_loop() { + let bind_ack: &[u8] = &[ + 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0xfd, 0x04, 0x01, 0x00, 0x04, 0x00, 0x31, 0x33, + 0x35, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x01, 0x02, 0x03, 0x04, + 0xFF, + ]; + let mut dcerpc_state = DCERPCState::new(); + dcerpc_state.data_needed_for_dir = core::STREAM_TOCLIENT; + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind_ack, core::STREAM_TOCLIENT) + ); + } + + #[test] + // Check for correct internal ids for bind_acks + pub fn test_parse_bindack_internal_ids() { + let bind1: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x50, 0x08, 0x43, 0x95, 0x43, 0x5a, 0x8b, 0xb2, 0xf4, 0xc5, + 0xb9, 0xee, 0x67, 0x55, 0x7c, 0x19, 0x00, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xda, 0xc2, 0xbc, 0x9b, 0x35, 0x2e, 0xd4, 0xc9, + 0x1f, 0x85, 0x01, 0xe6, 0x4e, 0x5a, 0x5e, 0xd4, 0x04, 0x00, 0x03, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0xb2, 0x97, 0xcc, 0x14, 0x6f, 0x70, + 0x0d, 0xa5, 0x33, 0xd7, 0xf4, 0xe3, 0x8e, 0xb2, 0x2a, 0x1e, 0x05, 0x00, 0x02, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x96, 0x4e, 0xa6, 0xf6, + 0xb2, 0x4b, 0xae, 0xb3, 0x21, 0xf4, 0x97, 0x7c, 0xcd, 0xa7, 0x08, 0xb0, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0xbc, 0xc0, + 0xf7, 0x71, 0x3f, 0x71, 0x54, 0x44, 0x22, 0xa8, 0x55, 0x0f, 0x98, 0x83, 0x1f, 0xfe, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, + 0xbe, 0x52, 0xf2, 0x58, 0x4a, 0xc3, 0xb5, 0xd0, 0xba, 0xac, 0xda, 0xf0, 0x12, 0x99, + 0x38, 0x6e, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x01, 0x00, 0xdb, 0xfa, 0x73, 0x01, 0xb3, 0x81, 0x01, 0xd4, 0x7f, 0xa0, 0x36, 0xb1, + 0x97, 0xae, 0x29, 0x7f, 0x01, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x00, 0x89, 0xbe, 0x41, 0x1d, 0x38, 0x75, 0xf5, 0xb5, 0xad, 0x27, + 0x73, 0xf1, 0xb0, 0x7a, 0x28, 0x82, 0x05, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0xf6, 0x87, 0x09, 0x93, 0xb8, 0xa8, 0x20, 0xc4, + 0xb8, 0x63, 0xe6, 0x95, 0xed, 0x59, 0xee, 0x3f, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x92, 0x77, 0x92, 0x68, 0x3e, 0xa4, + 0xbc, 0x3f, 0x44, 0x33, 0x0e, 0xb8, 0x33, 0x0a, 0x2f, 0xdf, 0x01, 0x00, 0x02, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0xa1, 0x03, 0xd2, 0xa9, + 0xd2, 0x16, 0xc9, 0x89, 0x67, 0x18, 0x3e, 0xb1, 0xee, 0x6b, 0xf9, 0x18, 0x02, 0x00, + 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x2f, 0x09, + 0x5e, 0x74, 0xec, 0xa0, 0xbb, 0xc1, 0x60, 0x18, 0xf1, 0x93, 0x04, 0x17, 0x11, 0xf9, + 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, + 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, + 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let bind_ack1: &[u8] = &[ + 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0xc1, 0x2b, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x50, + 0x49, 0x50, 0x45, 0x5c, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let bind2: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0xc7, 0x70, 0x0d, 0x3e, 0x71, 0x37, 0x39, 0x0d, 0x3a, 0x4f, + 0xd3, 0xdc, 0xca, 0x49, 0xe8, 0xa3, 0x05, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x84, 0xb6, 0x55, 0x75, 0xdb, 0x9e, 0xba, 0x54, + 0x56, 0xd3, 0x45, 0x10, 0xb7, 0x7a, 0x2a, 0xe2, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x6e, 0x39, 0x21, 0x24, 0x70, 0x6f, + 0x41, 0x57, 0x54, 0x70, 0xb8, 0xc3, 0x5e, 0x89, 0x3b, 0x43, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x39, 0x6a, 0x86, 0x5d, + 0x24, 0x0f, 0xd2, 0xf7, 0xb6, 0xce, 0x95, 0x9c, 0x54, 0x1d, 0x3a, 0xdb, 0x02, 0x00, + 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x12, 0xa5, + 0xdd, 0xc5, 0x55, 0xce, 0xc3, 0x46, 0xbd, 0xa0, 0x94, 0x39, 0x3c, 0x0d, 0x9b, 0x5b, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, + 0x87, 0x1c, 0x8b, 0x6e, 0x11, 0xa8, 0x67, 0x98, 0xd4, 0x5d, 0xf6, 0x8a, 0x2f, 0x33, + 0x24, 0x7b, 0x05, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x9b, 0x82, 0x13, 0xd1, 0x28, 0xe0, 0x63, 0xf3, 0x62, 0xee, 0x76, 0x73, + 0xf9, 0xac, 0x3d, 0x2e, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x00, 0xa9, 0xd4, 0x73, 0xf2, 0xed, 0xad, 0xe8, 0x82, 0xf8, 0xcf, + 0x9d, 0x9f, 0x66, 0xe6, 0x43, 0x37, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x06, 0x2b, 0x85, 0x38, 0x4f, 0x73, 0x96, 0xb1, + 0x73, 0xe1, 0x59, 0xbe, 0x9d, 0xe2, 0x6c, 0x07, 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xbf, 0xfa, 0xbb, 0xa4, 0x9e, 0x5c, + 0x80, 0x61, 0xb5, 0x8b, 0x79, 0x69, 0xa6, 0x32, 0x88, 0x77, 0x01, 0x00, 0x01, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x39, 0xa8, 0x2c, 0x39, + 0x73, 0x50, 0x06, 0x8d, 0xf2, 0x37, 0x1e, 0x1e, 0xa8, 0x8f, 0x46, 0x98, 0x02, 0x00, + 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x91, 0x13, + 0xd0, 0xa7, 0xef, 0xc4, 0xa7, 0x96, 0x0c, 0x4a, 0x0d, 0x29, 0x80, 0xd3, 0xfe, 0xbf, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, + 0xcc, 0x2b, 0x55, 0x1d, 0xd4, 0xa4, 0x0d, 0xfb, 0xcb, 0x6f, 0x86, 0x36, 0xa6, 0x57, + 0xc3, 0x21, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x01, 0x00, 0x43, 0x7b, 0x07, 0xee, 0x85, 0xa8, 0xb9, 0x3a, 0x0f, 0xf9, 0x83, 0x70, + 0xe6, 0x0b, 0x4f, 0x33, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x01, 0x00, 0x9c, 0x6a, 0x15, 0x8c, 0xd6, 0x9c, 0xa6, 0xc3, 0xb2, 0x9e, + 0x62, 0x9f, 0x3d, 0x8e, 0x47, 0x73, 0x02, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, + 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, + ]; + let bind_ack2: &[u8] = &[ + 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0xc2, 0x2b, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x50, + 0x49, 0x50, 0x45, 0x5c, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let bind3: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0xa4, 0x7f, 0x8e, 0xc6, 0xef, 0x56, 0x9b, 0x63, 0x92, 0xfa, + 0x08, 0xb3, 0x35, 0xe2, 0xa5, 0x81, 0x00, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x9f, 0xfc, 0x78, 0xd2, 0x5f, 0x16, 0x0b, 0xbc, + 0xc6, 0xdb, 0x5d, 0xef, 0xde, 0x54, 0xa2, 0x6f, 0x04, 0x00, 0x01, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x78, 0xb8, 0x96, 0xc7, 0x2f, 0xda, + 0x11, 0x6b, 0xd1, 0x28, 0x68, 0xe1, 0xd6, 0x71, 0xac, 0x9d, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xcf, 0xf4, 0xd7, 0x37, + 0x03, 0xda, 0xcc, 0xe3, 0x3e, 0x34, 0x7f, 0x67, 0x99, 0x91, 0x41, 0x3d, 0x01, 0x00, + 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x48, 0xeb, + 0x32, 0xf0, 0x27, 0xd5, 0x9d, 0xd0, 0x1e, 0xc6, 0x48, 0x46, 0x97, 0xe9, 0xdb, 0x09, + 0x05, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, + 0x82, 0xec, 0x0d, 0x08, 0xf2, 0x8f, 0x22, 0x57, 0x42, 0x9b, 0xce, 0xa8, 0x74, 0x16, + 0xc6, 0xec, 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x2e, 0x00, 0x70, 0x44, 0xee, 0xc9, 0x30, 0x6b, 0xf4, 0x34, 0x1e, 0x3d, + 0x35, 0x0f, 0xf7, 0xf7, 0x00, 0x00, 0x01, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x00, 0x59, 0x04, 0x39, 0x3f, 0x59, 0x87, 0x14, 0x0e, 0x76, 0x8d, + 0x17, 0xc2, 0x47, 0xfa, 0x67, 0x7f, 0x04, 0x00, 0x02, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x30, 0xd6, 0xed, 0x2e, 0x57, 0xfa, 0xf4, 0x72, + 0x6c, 0x10, 0x0d, 0xe5, 0x51, 0x7f, 0xd0, 0x39, 0x02, 0x00, 0x01, 0x00, 0x04, 0x5d, + 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0xea, 0x8b, 0x84, 0x4d, 0x44, 0x43, + 0xc1, 0x94, 0x75, 0xe2, 0x81, 0x48, 0xd8, 0x77, 0xd9, 0xce, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, + 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x89, 0x4f, 0xe7, 0x95, + 0xa3, 0xc1, 0x62, 0x36, 0x26, 0x9e, 0x67, 0xdb, 0x2c, 0x52, 0x89, 0xd3, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, + 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x78, 0x56, + 0x34, 0x12, 0x34, 0x12, 0xcd, 0xab, 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let bind_ack3: &[u8] = &[ + 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x1a, 0x33, 0x00, 0x00, 0x0e, 0x00, 0x5c, 0x70, + 0x69, 0x70, 0x65, 0x5c, 0x73, 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x73, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, + 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let mut dcerpc_state = DCERPCState::new(); + let expected_uuid1 = vec![ + 0x4b, 0x32, 0x4f, 0xc8, 0x16, 0x70, 0x01, 0xd3, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, + 0xe1, 0x88, + ]; + let expected_uuid2 = vec![ + 0x4b, 0x32, 0x4f, 0xc8, 0x16, 0x70, 0x01, 0xd3, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, + 0xe1, 0x88, + ]; + let expected_uuid3 = vec![ + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0xab, 0xcd, 0xef, 0x00, 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, + ]; + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind_ack1, core::STREAM_TOCLIENT) + ); + if let Some(ref back) = dcerpc_state.bindack { + assert_eq!(1, back.accepted_uuid_list.len()); + assert_eq!(12, back.accepted_uuid_list[0].ctxid); + assert_eq!(expected_uuid1, back.accepted_uuid_list[0].uuid); + } + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind2, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind_ack2, core::STREAM_TOCLIENT) + ); + if let Some(ref back) = dcerpc_state.bindack { + assert_eq!(1, back.accepted_uuid_list.len()); + assert_eq!(15, back.accepted_uuid_list[0].ctxid); + assert_eq!(expected_uuid2, back.accepted_uuid_list[0].uuid); + } + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind3, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(&bind_ack3, core::STREAM_TOCLIENT) + ); + if let Some(ref back) = dcerpc_state.bindack { + assert_eq!(1, back.accepted_uuid_list.len()); + dcerpc_state.data_needed_for_dir = core::STREAM_TOSERVER; + assert_eq!(11, back.accepted_uuid_list[0].ctxid); + assert_eq!(expected_uuid3, back.accepted_uuid_list[0].uuid); + } + } + + #[test] + pub fn test_bind_acks_alter_contexts_internal_ids() { + let bind: &[u8] = &[ + 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x40, 0xfd, 0x2c, 0x34, 0x6c, 0x3c, 0xce, 0x11, 0xa8, 0x93, + 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let bindack: &[u8] = &[ + 0x05, 0x00, 0x0c, 0x03, 0x10, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x0d, 0x00, 0x5c, 0x70, + 0x69, 0x70, 0x65, 0x5c, 0x6c, 0x6c, 0x73, 0x72, 0x70, 0x63, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, + 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + let alter_context: &[u8] = &[ + 0x05, 0x00, 0x0e, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0xd0, 0x4c, 0x67, 0x57, 0x00, 0x52, 0xce, 0x11, 0xa8, 0x97, + 0x08, 0x00, 0x2b, 0x2e, 0x9c, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let alter_context_resp: &[u8] = &[ + 0x05, 0x00, 0x0f, 0x03, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10, 0x7d, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, + 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00, + ]; + + let mut dcerpc_state = DCERPCState::new(); + let expected_uuid1 = vec![ + 0x34, 0x2c, 0xfd, 0x40, 0x3c, 0x6c, 0x11, 0xce, 0xa8, 0x93, 0x08, 0x00, 0x2b, 0x2e, + 0x9c, 0x6d, + ]; + let expected_uuid2 = vec![ + 0x57, 0x67, 0x4c, 0xd0, 0x52, 0x00, 0x11, 0xce, 0xa8, 0x97, 0x08, 0x00, 0x2b, 0x2e, + 0x9c, 0x6d, + ]; + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(bind, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(bindack, core::STREAM_TOCLIENT) + ); + if let Some(ref back) = dcerpc_state.bindack { + assert_eq!(1, back.accepted_uuid_list.len()); + assert_eq!(0, back.accepted_uuid_list[0].ctxid); + assert_eq!(expected_uuid1, back.accepted_uuid_list[0].uuid); + } + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(alter_context, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(alter_context_resp, core::STREAM_TOCLIENT) + ); + if let Some(ref back) = dcerpc_state.bindack { + assert_eq!(1, back.accepted_uuid_list.len()); + assert_eq!(1, back.accepted_uuid_list[0].ctxid); + assert_eq!(expected_uuid2, back.accepted_uuid_list[0].uuid); + } + } + + #[test] + pub fn test_parse_dcerpc_frag_3() { + let request1: &[u8] = &[ + 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x0c, 0x00, + ]; + let request2: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF, + ]; + let mut dcerpc_state = DCERPCState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(request1, core::STREAM_TOSERVER) + ); + assert_eq!( + AppLayerResult::ok(), + dcerpc_state.handle_input_data(request2, core::STREAM_TOSERVER) + ); + if let Some(ref req) = dcerpc_state.request { + assert_eq!(2, req.opnum); + assert_eq!(0, req.ctxid); + assert_eq!(14, req.stub_data_buffer_len); + } + } +} diff --git a/rust/src/dcerpc/dcerpc_udp.rs b/rust/src/dcerpc/dcerpc_udp.rs new file mode 100644 index 0000000000..bf69611787 --- /dev/null +++ b/rust/src/dcerpc/dcerpc_udp.rs @@ -0,0 +1,512 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use std::mem::transmute; + +use crate::applayer::AppLayerResult; +use crate::core; +use crate::dcerpc::dcerpc::{ + DCERPCRequest, DCERPCResponse, DCERPCUuidEntry, DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, + PFC_FIRST_FRAG, +}; +use crate::dcerpc::parser; +use crate::log::*; +use std::cmp; + +// Constant DCERPC UDP Header length +pub const DCERPC_UDP_HDR_LEN: i32 = 80; + +#[derive(Debug)] +pub struct DCERPCHdrUdp { + pub rpc_vers: u8, + pub pkt_type: u8, + pub flags1: u8, + pub flags2: u8, + pub drep: Vec, + pub serial_hi: u8, + pub objectuuid: Vec, + pub interfaceuuid: Vec, + pub activityuuid: Vec, + pub server_boot: u32, + pub if_vers: u32, + pub seqnum: u32, + pub opnum: u16, + pub ihint: u16, + pub ahint: u16, + pub fraglen: u16, + pub fragnum: u16, + pub auth_proto: u8, + pub serial_lo: u8, +} + +#[derive(Debug)] +pub struct DCERPCUDPState { + pub header: Option, + pub request: Option, + pub response: Option, + pub fraglenleft: u16, + pub uuid_entry: Option, + pub uuid_list: Vec, + pub de_state: Option<*mut core::DetectEngineState>, +} + +impl DCERPCUDPState { + pub fn new() -> DCERPCUDPState { + return DCERPCUDPState { + header: None, + request: None, + response: None, + fraglenleft: 0, + uuid_entry: None, + uuid_list: Vec::new(), + de_state: None, + }; + } + + fn new_request(&mut self) { + let request = DCERPCRequest::new(); + self.request = Some(request); + } + + fn new_response(&mut self) { + let response = DCERPCResponse::new(); + self.response = Some(response); + } + fn create_new_query(&mut self, pkt_type: u8) { + match pkt_type { + DCERPC_TYPE_REQUEST => { + self.new_request(); + } + DCERPC_TYPE_RESPONSE => { + self.new_response(); + } + _ => { + SCLogDebug!("Unrecognized packet type"); + } + } + } + + fn get_hdr_pkt_type(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = &self.header { + return Some(hdr.pkt_type); + } + // Shouldn't happen + None + } + + fn get_hdr_flags1(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = &self.header { + return Some(hdr.flags1); + } + // Shouldn't happen + None + } + + pub fn get_hdr_fraglen(&self) -> Option { + debug_validate_bug_on!(self.header.is_none()); + if let Some(ref hdr) = &self.header { + return Some(hdr.fraglen); + } + // Shouldn't happen + None + } + + pub fn handle_fragment_data(&mut self, input: &[u8], input_len: u16) -> u16 { + let mut retval: u16 = 0; + let hdrflags1 = self.get_hdr_flags1().unwrap_or(0); + let fraglenleft = self.fraglenleft; + + // Update the stub params based on the packet type + match self.get_hdr_pkt_type().unwrap_or(0) { + DCERPC_TYPE_REQUEST => { + if let Some(ref mut req) = self.request { + retval = evaluate_stub_params( + input, + input_len, + hdrflags1, + fraglenleft, + &mut req.stub_data_buffer, + &mut req.stub_data_buffer_len, + ); + } + } + DCERPC_TYPE_RESPONSE => { + if let Some(ref mut resp) = self.response { + retval = evaluate_stub_params( + input, + input_len, + hdrflags1, + fraglenleft, + &mut resp.stub_data_buffer, + &mut resp.stub_data_buffer_len, + ); + } + } + _ => { + SCLogDebug!("Unrecognized packet type"); + return 0; + } + } + // Update the remaining fragment length + self.fraglenleft -= retval; + + retval + } + + pub fn process_header(&mut self, input: &[u8]) -> i32 { + match parser::parse_dcerpc_udp_header(input) { + Ok((leftover_bytes, header)) => { + if header.rpc_vers != 4 { + SCLogDebug!("DCERPC UDP Header did not validate."); + return -1; + } + let mut uuidentry = DCERPCUuidEntry::new(); + let auuid = header.activityuuid.to_vec(); + uuidentry.uuid = auuid; + self.uuid_list.push(uuidentry); + self.header = Some(header); + (input.len() - leftover_bytes.len()) as i32 + } + Err(nom::Err::Incomplete(_)) => { + // Insufficient data. + SCLogDebug!("Insufficient data while parsing DCERPC request"); + -1 + } + Err(_) => { + // Error, probably malformed data. + SCLogDebug!("An error occurred while parsing DCERPC request"); + -1 + } + } + } + + pub fn handle_input_data(&mut self, input: &[u8]) -> AppLayerResult { + // Input length should at least be header length + if (input.len() as i32) < DCERPC_UDP_HDR_LEN { + return AppLayerResult::err(); + } + // Call header parser first + let mut parsed = self.process_header(input); + if parsed == -1 { + return AppLayerResult::err(); + } + + let mut input_left = input.len() as i32 - parsed; + let pkt_type = self.get_hdr_pkt_type().unwrap_or(0); + let fraglen = self.get_hdr_fraglen().unwrap_or(0); + self.fraglenleft = fraglen; + self.create_new_query(pkt_type); + // Parse rest of the body + while parsed >= DCERPC_UDP_HDR_LEN && parsed < fraglen as i32 && input_left > 0 { + let retval = self.handle_fragment_data(&input[parsed as usize..], input_left as u16); + if retval > 0 && retval <= input_left as u16 { + parsed += retval as i32; + input_left -= retval as i32; + } else if input_left > 0 { + SCLogDebug!("Error parsing DCERPC UDP Fragment Data"); + parsed -= input_left; + input_left = 0; + } + } + return AppLayerResult::ok(); + } +} + +fn evaluate_stub_params( + input: &[u8], + input_len: u16, + hdrflags: u8, + lenleft: u16, + stub_data_buffer: &mut Vec, + stub_data_buffer_len: &mut u16, +) -> u16 { + let stub_len: u16; + stub_len = cmp::min(lenleft, input_len); + if stub_len == 0 { + return 0; + } + // If the UDP frag is the the first frag irrespective of it being a part of + // a multi frag PDU or not, it indicates the previous PDU's stub would + // have been buffered and processed and we can use the buffer to hold + // frags from a fresh request/response + if hdrflags & PFC_FIRST_FRAG > 0 { + *stub_data_buffer_len = 0; + } + + let input_slice = &input[..stub_len as usize]; + stub_data_buffer.extend_from_slice(&input_slice); + *stub_data_buffer_len += stub_len; + + stub_len +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_parse( + _flow: *mut core::Flow, + state: &mut DCERPCUDPState, + _pstate: *mut std::os::raw::c_void, + input: *const u8, + input_len: u32, + _data: *mut std::os::raw::c_void, + _flags: u8, +) -> AppLayerResult { + if input_len > 0 && input != std::ptr::null_mut() { + let buf = build_slice!(input, input_len as usize); + return state.handle_input_data(buf); + } + AppLayerResult::err() +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_state_free(state: *mut std::os::raw::c_void) { + let _drop: Box = unsafe { transmute(state) }; +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_udp_state_new() -> *mut std::os::raw::c_void { + let state = DCERPCUDPState::new(); + let boxed = Box::new(state); + transmute(boxed) +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_state_transaction_free( + _state: *mut std::os::raw::c_void, + _tx_id: u64, +) { + // do nothing +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_get_tx_detect_state( + vtx: *mut std::os::raw::c_void, +) -> *mut core::DetectEngineState { + let dce_state = cast_pointer!(vtx, DCERPCUDPState); + match dce_state.de_state { + Some(ds) => ds, + None => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_set_tx_detect_state( + vtx: *mut std::os::raw::c_void, + de_state: *mut core::DetectEngineState, +) -> u8 { + let dce_state = cast_pointer!(vtx, DCERPCUDPState); + dce_state.de_state = Some(de_state); + 0 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_get_tx( + state: *mut std::os::raw::c_void, + _tx_id: u64, +) -> *mut DCERPCUDPState { + let dce_state = cast_pointer!(state, DCERPCUDPState); + dce_state +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_get_tx_cnt(_state: *mut std::os::raw::c_void) -> u8 { + 1 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_get_alstate_progress( + _tx: *mut std::os::raw::c_void, + _direction: u8, +) -> u8 { + 0 +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_udp_get_alstate_progress_completion_status(_direction: u8) -> u8 { + 1 +} + +#[cfg(test)] +mod tests { + use crate::applayer::AppLayerResult; + use crate::dcerpc::dcerpc_udp::DCERPCUDPState; + + #[test] + fn test_process_header_udp_incomplete_hdr() { + let request: &[u8] = &[ + 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, + 0x1c, 0x7d, 0xcf, 0x11, + ]; + + let mut dcerpcudp_state = DCERPCUDPState::new(); + assert_eq!(-1, dcerpcudp_state.process_header(request)); + } + + #[test] + fn test_process_header_udp_perfect_hdr() { + let request: &[u8] = &[ + 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, + 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57, 0x86, 0xc2, + 0x37, 0x67, 0xf7, 0x1e, 0xd1, 0x11, 0xbc, 0xd9, 0x00, 0x60, 0x97, 0x92, 0xd2, 0x6c, + 0x79, 0xbe, 0x01, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x68, 0x00, 0x00, 0x00, 0x0a, 0x00, + ]; + let mut dcerpcudp_state = DCERPCUDPState::new(); + assert_eq!(80, dcerpcudp_state.process_header(request)); + } + + #[test] + fn test_handle_fragment_data_udp_no_body() { + let request: &[u8] = &[ + 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, + 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57, 0x86, 0xc2, + 0x37, 0x67, 0xf7, 0x1e, 0xd1, 0x11, 0xbc, 0xd9, 0x00, 0x60, 0x97, 0x92, 0xd2, 0x6c, + 0x79, 0xbe, 0x01, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x68, 0x00, 0x00, 0x00, 0x0a, 0x00, + ]; + let mut dcerpcudp_state = DCERPCUDPState::new(); + assert_eq!( + 0, + dcerpcudp_state.handle_fragment_data(request, request.len() as u16) + ); + } + + #[test] + fn test_handle_input_data_udp_full_body() { + let request: &[u8] = &[ + 0x04, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x3f, 0x98, + 0xf0, 0x5c, 0xd9, 0x63, 0xcc, 0x46, 0xc2, 0x74, 0x51, 0x6c, 0x8a, 0x53, 0x7d, 0x6f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x70, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x24, 0x58, 0xfd, 0xcc, 0x45, + 0x64, 0x49, 0xb0, 0x70, 0xdd, 0xae, 0x74, 0x2c, 0x96, 0xd2, 0x60, 0x5e, 0x0d, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x5e, 0x0d, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x7c, 0x5e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x80, 0x96, 0xf1, 0xf1, 0x2a, 0x4d, 0xce, 0x11, 0xa6, 0x6a, 0x00, 0x20, 0xaf, 0x6e, + 0x72, 0xf4, 0x0c, 0x00, 0x00, 0x00, 0x4d, 0x41, 0x52, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xf4, + 0x0b, 0x00, 0x10, 0x09, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, + 0x04, 0x00, 0x00, 0x00, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x08, + 0x00, 0x00, 0xd8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xc8, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, 0xd8, 0x08, + 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x28, 0xcd, 0x00, 0x64, 0x29, 0xcd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xab, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xa5, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x46, 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xad, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x50, 0x00, 0x00, 0x00, + 0x4f, 0xb6, 0x88, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x66, 0x00, 0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x19, 0x0c, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x70, 0xd8, + 0x98, 0x93, 0x98, 0x4f, 0xd2, 0x11, 0xa9, 0x3d, 0xbe, 0x57, 0xb2, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x31, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x80, 0x00, + 0x00, 0x00, 0x0d, 0xf0, 0xad, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x43, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, + 0x04, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x81, 0xc5, 0x17, 0x03, 0x80, 0x0e, 0xe9, 0x4a, + 0x99, 0x99, 0xf1, 0x8a, 0x50, 0x6f, 0x7a, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, + 0xcc, 0xcc, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0xda, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2f, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x46, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, + 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xff, 0xff, 0x68, 0x8b, 0x0b, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x02, 0x00, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x9d, 0x13, 0x00, 0x01, 0xcc, 0xe0, 0xfd, 0x7f, + 0xcc, 0xe0, 0xfd, 0x7f, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, + ]; + let mut dcerpcudp_state = DCERPCUDPState::new(); + assert_eq!( + AppLayerResult::ok(), + dcerpcudp_state.handle_input_data(request) + ); + assert_eq!(0, dcerpcudp_state.fraglenleft); + if let Some(req) = dcerpcudp_state.request { + assert_eq!(1392, req.stub_data_buffer_len); + } + } +} diff --git a/rust/src/dcerpc/detect.rs b/rust/src/dcerpc/detect.rs new file mode 100644 index 0000000000..5d798a65e0 --- /dev/null +++ b/rust/src/dcerpc/detect.rs @@ -0,0 +1,504 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use super::dcerpc::{ + DCERPCState, DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, DCERPC_UUID_ENTRY_FLAG_FF, +}; +use crate::log::*; +use std::ffi::CStr; +use std::os::raw::{c_char, c_void}; +use uuid::Uuid; + +pub const DETECT_DCE_IFACE_OP_NONE: u8 = 0; +pub const DETECT_DCE_IFACE_OP_LT: u8 = 1; +pub const DETECT_DCE_IFACE_OP_GT: u8 = 2; +pub const DETECT_DCE_IFACE_OP_EQ: u8 = 3; +pub const DETECT_DCE_IFACE_OP_NE: u8 = 4; + +pub const DETECT_DCE_OPNUM_RANGE_UNINITIALIZED: u32 = 100000; + +#[derive(Debug)] +pub struct DCEIfaceData { + pub if_uuid: Vec, + pub op: u8, + pub version: u16, + pub any_frag: u8, +} + +#[derive(Debug)] +pub struct DCEOpnumRange { + pub range1: u32, + pub range2: u32, +} + +impl DCEOpnumRange { + pub fn new() -> DCEOpnumRange { + return DCEOpnumRange { + range1: DETECT_DCE_OPNUM_RANGE_UNINITIALIZED, + range2: DETECT_DCE_OPNUM_RANGE_UNINITIALIZED, + }; + } +} + +#[derive(Debug)] +pub struct DCEOpnumData { + pub data: Vec, +} + +fn extract_op_version(opver: &str) -> Result<(u8, u16), ()> { + let (op, version) = opver.split_at(1); + let opval: u8 = match op { + ">" => DETECT_DCE_IFACE_OP_GT, + "<" => DETECT_DCE_IFACE_OP_LT, + "=" => DETECT_DCE_IFACE_OP_EQ, + "!" => DETECT_DCE_IFACE_OP_NE, + _ => DETECT_DCE_IFACE_OP_NONE, + }; + + let version: u16 = match version.parse::() { + Ok(res) => res, + _ => { + return Err(()); + } + }; + if opval == DETECT_DCE_IFACE_OP_NONE + || (opval == DETECT_DCE_IFACE_OP_LT && version == std::u16::MIN) + || (opval == DETECT_DCE_IFACE_OP_GT && version == std::u16::MAX) + { + return Err(()); + } + + Ok((opval, version)) +} + +fn match_iface_version(version: u16, if_data: &DCEIfaceData) -> bool { + match if_data.op { + DETECT_DCE_IFACE_OP_LT => version < if_data.version, + DETECT_DCE_IFACE_OP_GT => version > if_data.version, + DETECT_DCE_IFACE_OP_EQ => version == if_data.version, + DETECT_DCE_IFACE_OP_NE => version != if_data.version, + _ => { + return true; + } + } +} + +fn match_backuuid(state: &mut DCERPCState, if_data: &mut DCEIfaceData) -> u8 { + let mut ret = 1; + if let Some(ref bindack) = state.bindack { + for uuidentry in bindack.accepted_uuid_list.iter() { + ret = 1; + // if any_frag is not enabled, we need to match only against the first fragment + if if_data.any_frag == 0 && (uuidentry.flags & DCERPC_UUID_ENTRY_FLAG_FF == 0) { + SCLogDebug!("any frag not enabled"); + continue; + } + // if the uuid has been rejected(uuidentry->result == 1), we skip to the next uuid + if uuidentry.result != 0 { + SCLogDebug!("Skipping to next UUID"); + continue; + } + + for i in 0..16 { + if if_data.if_uuid[i] != uuidentry.uuid[i] { + SCLogDebug!("Iface UUID and BINDACK Accepted UUID does not match"); + ret = 0; + break; + } + } + let ctxid = state.get_req_ctxid().unwrap_or(0); + ret = ret & ((uuidentry.ctxid == ctxid) as u8); + if ret == 0 { + SCLogDebug!("CTX IDs/UUIDs do not match"); + continue; + } + + if if_data.op != DETECT_DCE_IFACE_OP_NONE + && !match_iface_version(uuidentry.version, if_data) + { + SCLogDebug!("Interface version did not match"); + ret &= 0; + } + + if ret == 1 { + return 1; + } + } + } + + return ret; +} + +fn parse_iface_data(arg: &str) -> Result { + let split_args: Vec<&str> = arg.split(',').collect(); + let mut op_version = (0, 0); + let mut any_frag: u8 = 0; + let if_uuid = match Uuid::parse_str(split_args[0]) { + Ok(res) => res.as_bytes().to_vec(), + _ => { + return Err(()); + } + }; + + match split_args.len() { + 1 => {} + 2 => match split_args[1] { + "any_frag" => { + any_frag = 1; + } + _ => { + op_version = match extract_op_version(split_args[1]) { + Ok((op, ver)) => (op, ver), + _ => { + return Err(()); + } + }; + } + }, + 3 => { + op_version = match extract_op_version(split_args[1]) { + Ok((op, ver)) => (op, ver), + _ => { + return Err(()); + } + }; + if split_args[2] != "any_frag" { + return Err(()); + } + any_frag = 1; + } + _ => { + return Err(()); + } + } + + Ok(DCEIfaceData { + if_uuid: if_uuid, + op: op_version.0, + version: op_version.1, + any_frag: any_frag, + }) +} + +fn convert_str_to_u32(arg: &str) -> Result { + match arg.parse::() { + Ok(res) => Ok(res), + _ => Err(()), + } +} + +fn parse_opnum_data(arg: &str) -> Result { + let split_args: Vec<&str> = arg.split(',').collect(); + let mut dce_opnum_data: Vec = Vec::new(); + for range in split_args.iter() { + let mut opnum_range = DCEOpnumRange::new(); + let split_range: Vec<&str> = range.split('-').collect(); + let split_len = split_range.len(); + + if (split_len > 0 && convert_str_to_u32(split_range[0]).is_err()) + || (split_len > 1 && convert_str_to_u32(split_range[1]).is_err()) + { + return Err(()); + } + match split_len { + 1 => { + opnum_range.range1 = convert_str_to_u32(split_range[0]).unwrap(); + } + 2 => { + let range1 = convert_str_to_u32(split_range[0]).unwrap(); + let range2 = convert_str_to_u32(split_range[1]).unwrap(); + if range2 < range1 { + return Err(()); + } + opnum_range.range1 = range1; + opnum_range.range2 = range2; + } + _ => { + return Err(()); + } + } + dce_opnum_data.push(opnum_range); + } + + Ok(DCEOpnumData { + data: dce_opnum_data, + }) +} + +#[no_mangle] +pub extern "C" fn rs_dcerpc_iface_match(state: &mut DCERPCState, if_data: &mut DCEIfaceData) -> u8 { + let first_req_seen = state.get_first_req_seen().unwrap_or(0); + if first_req_seen == 0 { + return 0; + } + + match state.get_hdr_type() { + Some(x) => match x { + DCERPC_TYPE_REQUEST | DCERPC_TYPE_RESPONSE => { + } + _ => { + return 0; + } + }, + None => { + return 0; + } + }; + + return match_backuuid(state, if_data); +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_iface_parse(carg: *const c_char) -> *mut c_void { + if carg.is_null() { + return std::ptr::null_mut(); + } + let arg = match CStr::from_ptr(carg).to_str() { + Ok(arg) => arg, + _ => { + return std::ptr::null_mut(); + } + }; + + match parse_iface_data(&arg) { + Ok(detect) => std::mem::transmute(Box::new(detect)), + Err(_) => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_iface_free(ptr: *mut c_void) { + if ptr != std::ptr::null_mut() { + let _: Box = std::mem::transmute(ptr); + } +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_opnum_match( + state: &mut DCERPCState, + opnum_data: &mut DCEOpnumData, +) -> u8 { + let opnum = state.get_req_opnum().unwrap_or(0); // TODO is the default to 0 OK? + for range in opnum_data.data.iter() { + if range.range2 == DETECT_DCE_OPNUM_RANGE_UNINITIALIZED { + if range.range1 == opnum as u32 { + return 1; + } + } else if range.range1 <= opnum as u32 && range.range2 >= opnum as u32 { + return 1; + } + } + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_opnum_parse(carg: *const c_char) -> *mut c_void { + if carg.is_null() { + return std::ptr::null_mut(); + } + let arg = match CStr::from_ptr(carg).to_str() { + Ok(arg) => arg, + _ => { + return std::ptr::null_mut(); + } + }; + + match parse_opnum_data(&arg) { + Ok(detect) => std::mem::transmute(Box::new(detect)), + Err(_) => std::ptr::null_mut(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn rs_dcerpc_opnum_free(ptr: *mut c_void) { + if ptr != std::ptr::null_mut() { + let _: Box = std::mem::transmute(ptr); + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_extract_op_version() { + let op_version = "<1"; + assert_eq!( + Ok((DETECT_DCE_IFACE_OP_LT, 1)), + extract_op_version(op_version) + ); + + let op_version = ">10"; + assert_eq!( + Ok((DETECT_DCE_IFACE_OP_GT, 10)), + extract_op_version(op_version) + ); + + let op_version = "=45"; + assert_eq!( + Ok((DETECT_DCE_IFACE_OP_EQ, 45)), + extract_op_version(op_version) + ); + + let op_version = "!0"; + assert_eq!( + Ok((DETECT_DCE_IFACE_OP_NE, 0)), + extract_op_version(op_version) + ); + + let op_version = "@1"; + assert_eq!(true, extract_op_version(op_version).is_err()); + } + + #[test] + fn test_match_iface_version() { + let iface_data = DCEIfaceData { + if_uuid: Vec::new(), + op: 3, + version: 10, + any_frag: 0, + }; + let version = 10; + assert_eq!(true, match_iface_version(version, &iface_data)); + + let version = 2; + assert_eq!(false, match_iface_version(version, &iface_data)); + } + + #[test] + fn test_parse_iface_data() { + let arg = "12345678-1234-1234-1234-123456789ABC"; + let iface_data = parse_iface_data(arg).unwrap(); + let expected_uuid = Ok(String::from("12345678-1234-1234-1234-123456789ABC").to_lowercase()); + let uuid = Uuid::from_slice(iface_data.if_uuid.as_slice()); + let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + assert_eq!(expected_uuid, uuid); + + let arg = "12345678-1234-1234-1234-123456789ABC,>1"; + let iface_data = parse_iface_data(arg).unwrap(); + let expected_uuid = Ok(String::from("12345678-1234-1234-1234-123456789ABC").to_lowercase()); + let uuid = Uuid::from_slice(iface_data.if_uuid.as_slice()); + let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + assert_eq!(expected_uuid, uuid); + assert_eq!(DETECT_DCE_IFACE_OP_GT, iface_data.op); + assert_eq!(1, iface_data.version); + + let arg = "12345678-1234-1234-1234-123456789ABC,any_frag"; + let iface_data = parse_iface_data(arg).unwrap(); + let expected_uuid = Ok(String::from("12345678-1234-1234-1234-123456789ABC").to_lowercase()); + let uuid = Uuid::from_slice(iface_data.if_uuid.as_slice()); + let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + assert_eq!(expected_uuid, uuid); + assert_eq!(DETECT_DCE_IFACE_OP_NONE, iface_data.op); + assert_eq!(1, iface_data.any_frag); + assert_eq!(0, iface_data.version); + + let arg = "12345678-1234-1234-1234-123456789ABC,!10,any_frag"; + let iface_data = parse_iface_data(arg).unwrap(); + let expected_uuid = Ok(String::from("12345678-1234-1234-1234-123456789ABC").to_lowercase()); + let uuid = Uuid::from_slice(iface_data.if_uuid.as_slice()); + let uuid = uuid.map(|uuid| uuid.to_hyphenated().to_string()); + assert_eq!(expected_uuid, uuid); + assert_eq!(DETECT_DCE_IFACE_OP_NE, iface_data.op); + assert_eq!(1, iface_data.any_frag); + assert_eq!(10, iface_data.version); + + let arg = "12345678-1234-1234-1234-123456789ABC,>1,ay_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-1234-1234-1234-12345679ABC,>1,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-1234-1234-134-123456789ABC,>1,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-123-124-1234-123456789ABC,>1,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "1234568-1234-1234-1234-123456789ABC,>1,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-1234-1234-1234-123456789ABC,>65536,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-1234-1234-1234-123456789ABC,>=1,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-1234-1234-1234-123456789ABC,<0,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + + let arg = "12345678-1234-1234-1234-123456789ABC,>65535,any_frag"; + let iface_data = parse_iface_data(arg); + assert_eq!(iface_data.is_err(), true); + } + + #[test] + fn test_parse_opnum_data() { + let arg = "12"; + let opnum_data = parse_opnum_data(arg).unwrap(); + assert_eq!(1, opnum_data.data.len()); + assert_eq!(12, opnum_data.data[0].range1); + assert_eq!( + DETECT_DCE_OPNUM_RANGE_UNINITIALIZED, + opnum_data.data[0].range2 + ); + + let arg = "12,24"; + let opnum_data = parse_opnum_data(arg).unwrap(); + assert_eq!(2, opnum_data.data.len()); + assert_eq!(12, opnum_data.data[0].range1); + assert_eq!(24, opnum_data.data[1].range1); + + let arg = "12,12-24"; + let opnum_data = parse_opnum_data(arg).unwrap(); + assert_eq!(2, opnum_data.data.len()); + assert_eq!(12, opnum_data.data[0].range1); + assert_eq!(12, opnum_data.data[1].range1); + assert_eq!(24, opnum_data.data[1].range2); + + let arg = "12-14,12,121,62-78"; + let opnum_data = parse_opnum_data(arg).unwrap(); + assert_eq!(4, opnum_data.data.len()); + assert_eq!(12, opnum_data.data[0].range1); + assert_eq!(14, opnum_data.data[0].range2); + assert_eq!(121, opnum_data.data[2].range1); + assert_eq!(78, opnum_data.data[3].range2); + + let arg = "12,26,62,61,6513-6666"; + let opnum_data = parse_opnum_data(arg).unwrap(); + assert_eq!(5, opnum_data.data.len()); + assert_eq!(61, opnum_data.data[3].range1); + assert_eq!(6513, opnum_data.data[4].range1); + + let arg = "12,26,62,61,6513--"; + let opnum_data = parse_opnum_data(arg); + assert_eq!(true, opnum_data.is_err()); + + let arg = "12-14,12,121,62-8"; + let opnum_data = parse_opnum_data(arg); + assert_eq!(true, opnum_data.is_err()); + } +} diff --git a/rust/src/dcerpc/mod.rs b/rust/src/dcerpc/mod.rs new file mode 100644 index 0000000000..6b17244dda --- /dev/null +++ b/rust/src/dcerpc/mod.rs @@ -0,0 +1,21 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +pub mod dcerpc; +pub mod dcerpc_udp; +pub mod parser; +pub mod detect; diff --git a/rust/src/dcerpc/parser.rs b/rust/src/dcerpc/parser.rs new file mode 100644 index 0000000000..0356479e89 --- /dev/null +++ b/rust/src/dcerpc/parser.rs @@ -0,0 +1,371 @@ +/* Copyright (C) 2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +use crate::dcerpc::dcerpc::{ + BindCtxItem, DCERPCBind, DCERPCBindAck, DCERPCBindAckResult, DCERPCHdr, DCERPCRequest, Uuid, +}; +use crate::dcerpc::dcerpc_udp::DCERPCHdrUdp; +use crate::log::*; +use nom::number::complete::{le_u16, le_u32, le_u8}; +use nom::number::Endianness; + +fn uuid_to_vec(uuid: Uuid) -> Vec { + let mut uuidtmp = uuid; + let mut vect: Vec = Vec::new(); + vect.append(&mut uuidtmp.time_low); + vect.append(&mut uuidtmp.time_mid); + vect.append(&mut uuidtmp.time_hi_and_version); + vect.push(uuidtmp.clock_seq_hi_and_reserved); + vect.push(uuidtmp.clock_seq_low); + vect.append(&mut uuidtmp.node); + vect +} + +fn assemble_uuid(uuid: Uuid) -> Vec { + let mut uuidtmp = uuid; + let mut vect: Vec = Vec::new(); + uuidtmp.time_low.reverse(); + uuidtmp.time_mid.reverse(); + uuidtmp.time_hi_and_version.reverse(); + vect.append(&mut uuidtmp.time_low); + vect.append(&mut uuidtmp.time_mid); + vect.append(&mut uuidtmp.time_hi_and_version); + vect.push(uuidtmp.clock_seq_hi_and_reserved); + vect.push(uuidtmp.clock_seq_low); + vect.append(&mut uuidtmp.node); + + vect +} + +named!(pub parse_uuid, + do_parse!( + time_low: take!(4) + >> time_mid: take!(2) + >> time_hi_and_version: take!(2) + >> clock_seq_hi_and_reserved: le_u8 + >> clock_seq_low: le_u8 + >> node: take!(6) + >> ( + Uuid { + time_low: time_low.to_vec(), + time_mid: time_mid.to_vec(), + time_hi_and_version: time_hi_and_version.to_vec(), + clock_seq_hi_and_reserved: clock_seq_hi_and_reserved, + clock_seq_low: clock_seq_low, + node: node.to_vec(), + } + ) + ) +); + +named!(pub parse_dcerpc_udp_header, + do_parse!( + rpc_vers: le_u8 + >> pkt_type: le_u8 + >> flags1: le_u8 + >> flags2: le_u8 + >> drep: take!(3) + >> endianness: value!(if drep[0] == 0 { Endianness::Big } else { Endianness::Little }) + >> serial_hi: le_u8 + >> objectuuid: take!(16) + >> interfaceuuid: take!(16) + >> activityuuid: take!(16) + >> server_boot: u32!(endianness) + >> if_vers: u32!(endianness) + >> seqnum: u32!(endianness) + >> opnum: u16!(endianness) + >> ihint: u16!(endianness) + >> ahint: u16!(endianness) + >> fraglen: u16!(endianness) + >> fragnum: u16!(endianness) + >> auth_proto: le_u8 + >> serial_lo: le_u8 + >> ( + DCERPCHdrUdp { + rpc_vers: rpc_vers, + pkt_type: pkt_type, + flags1: flags1, + flags2: flags2, + drep: drep.to_vec(), + serial_hi: serial_hi, + objectuuid: match parse_uuid(objectuuid) { + Ok((_, vect)) => assemble_uuid(vect), + Err(e) => { + SCLogDebug!("{}", e); + vec![0] + }, + }, + interfaceuuid: match parse_uuid(interfaceuuid) { + Ok((_, vect)) => assemble_uuid(vect), + Err(e) => { + SCLogDebug!("{}", e); + vec![0] + }, + }, + activityuuid: match parse_uuid(activityuuid){ + Ok((_, vect)) => assemble_uuid(vect), + Err(e) => { + SCLogDebug!("{}", e); + vec![0] + }, + }, + server_boot: server_boot, + if_vers: if_vers, + seqnum: seqnum, + opnum: opnum, + ihint: ihint, + ahint: ahint, + fraglen: fraglen, + fragnum: fragnum, + auth_proto: auth_proto, + serial_lo: serial_lo, + } + ) + ) +); + +named!(pub parse_dcerpc_bindack_result, + do_parse!( + ack_result: le_u16 + >> ack_reason: le_u16 + >> transfer_syntax: take!(16) + >> syntax_version: le_u32 + >> ( + DCERPCBindAckResult { + ack_result:ack_result, + ack_reason:ack_reason, + transfer_syntax:transfer_syntax.to_vec(), + syntax_version:syntax_version, + } + ) + ) +); + +named!(pub parse_dcerpc_bindack, + do_parse!( + _max_xmit_frag: le_u16 + >> _max_recv_frag: le_u16 + >> _assoc_group: take!(4) + >> sec_addr_len: le_u16 + >> take!(sec_addr_len) + >> cond!((sec_addr_len + 2) % 4 != 0, take!(4 - (sec_addr_len + 2) % 4)) + >> numctxitems: le_u8 + >> take!(3) // Padding + >> ctxitems: count!(parse_dcerpc_bindack_result, numctxitems as usize) + >> ( + DCERPCBindAck { + accepted_uuid_list: Vec::new(), + sec_addr_len: sec_addr_len, + numctxitems: numctxitems, + ctxitems: ctxitems, + } + ) + ) +); + +named_args!(pub parse_bindctx_item(endianness: Endianness) , + do_parse!( + ctxid: u16!(endianness) + >> _num_trans_items: le_u8 + >> take!(1) // Reservid bit + >> uuid: take!(16) + >> version: u16!(endianness) + >> versionminor: u16!(endianness) + >> take!(20) + >> ( + BindCtxItem { + ctxid: ctxid, + // UUID parsing for TCP seems to change as per endianness + uuid: match parse_uuid(uuid) { + Ok((_, vect)) => match endianness { + Endianness::Little => assemble_uuid(vect), + _ => uuid_to_vec(vect), + }, + // Shouldn't happen + Err(_e) => {vec![0]}, + }, + version: version, + versionminor: versionminor, + } + ) + ) +); + +named!(pub parse_dcerpc_bind, + do_parse!( + _max_xmit_frag: le_u16 + >> _max_recv_frag: le_u16 + >> _assoc_group_id: le_u32 + >> numctxitems: le_u8 + >> take!(3) + >> ( + DCERPCBind { + numctxitems: numctxitems, + uuid_list: Vec::new(), + } + ) + ) +); + +named!(pub parse_dcerpc_header, + do_parse!( + rpc_vers: le_u8 + >> rpc_vers_minor: le_u8 + >> hdrtype: le_u8 + >> pfc_flags: le_u8 + >> packed_drep: take!(4) + >> endianness: value!(if packed_drep[0] & 0x10 == 0 { Endianness::Big } else { Endianness::Little }) + >> frag_length: u16!(endianness) + >> auth_length: u16!(endianness) + >> call_id: u32!(endianness) + >> ( + DCERPCHdr { + rpc_vers: rpc_vers, + rpc_vers_minor: rpc_vers_minor, + hdrtype: hdrtype, + pfc_flags: pfc_flags, + packed_drep: packed_drep.to_vec(), + frag_length: frag_length, + auth_length: auth_length, + call_id: call_id, + } + ) + ) +); + +named_args!(pub parse_dcerpc_request(endianness: Endianness) , + do_parse!( + _pad: take!(4) + >> ctxid: u16!(endianness) + >> opnum: u16!(endianness) + >> ( + DCERPCRequest { + ctxid: ctxid, + opnum: opnum, + first_request_seen: 1, + stub_data_buffer: Vec::new(), + stub_data_buffer_len: 0, + stub_data_buffer_reset: false, + cmd: 0, + } + ) + ) +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_uuid() { + let uuid: &[u8] = &[ + 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, + 0x7c, 0x57, + ]; + let expected_uuid = Uuid { + time_low: vec![0xb8, 0x4a, 0x9f, 0x4d], + time_mid: vec![0x1c, 0x7d], + time_hi_and_version: vec![0xcf, 0x11], + clock_seq_hi_and_reserved: 0x86, + clock_seq_low: 0x1e, + node: vec![0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57], + }; + let (_remainder, parsed_uuid) = parse_uuid(uuid).unwrap(); + assert_eq!(expected_uuid, parsed_uuid); + } + + #[test] + fn test_assemble_uuid() { + let uuid = Uuid { + time_low: vec![0xb8, 0x4a, 0x9f, 0x4d], + time_mid: vec![0x1c, 0x7d], + time_hi_and_version: vec![0xcf, 0x11], + clock_seq_hi_and_reserved: 0x86, + clock_seq_low: 0x1e, + node: vec![0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57], + }; + let expected_val = vec![ + 0x4d, 0x9f, 0x4a, 0xb8, 0x7d, 0x1c, 0x11, 0xcf, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, + 0x7c, 0x57, + ]; + assert_eq!(expected_val, assemble_uuid(uuid)); + } + + #[test] + fn test_parse_dcerpc_udp_header() { + let dcerpcheader: &[u8] = &[ + 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x4a, 0x9f, 0x4d, + 0x1c, 0x7d, 0xcf, 0x11, 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57, 0x86, 0xc2, + 0x37, 0x67, 0xf7, 0x1e, 0xd1, 0x11, 0xbc, 0xd9, 0x00, 0x60, 0x97, 0x92, 0xd2, 0x6c, + 0x79, 0xbe, 0x01, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x68, 0x00, 0x00, 0x00, 0x0a, 0x00, + ]; + let (_remainder, header) = parse_dcerpc_udp_header(dcerpcheader).unwrap(); + let expected_activityuuid = vec![ + 0x67, 0x37, 0xc2, 0x86, 0x1e, 0xf7, 0x11, 0xd1, 0xbc, 0xd9, 0x00, 0x60, 0x97, 0x92, + 0xd2, 0x6c, + ]; + assert_eq!(0x04, header.rpc_vers); + assert_eq!(0x00, header.pkt_type); + assert_eq!(0x08, header.flags1); + assert_eq!(0x00, header.flags2); + assert_eq!(vec!(0x10, 0x00, 0x00), header.drep); + assert_eq!(0x00, header.serial_hi); + assert_eq!(expected_activityuuid, header.activityuuid); + assert_eq!(0x3401be79, header.server_boot); + assert_eq!(0x00000000, header.seqnum); + assert_eq!(0xffff, header.ihint); + assert_eq!(0x0068, header.fraglen); + assert_eq!(0x0a, header.auth_proto); + } + + #[test] + fn test_parse_dcerpc_header() { + let dcerpcheader: &[u8] = &[ + 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + ]; + let (_remainder, header) = parse_dcerpc_header(dcerpcheader).unwrap(); + assert_eq!(5, header.rpc_vers); + assert_eq!(0, header.rpc_vers_minor); + assert_eq!(0, header.hdrtype); + assert_eq!(1024, header.frag_length); + } + + #[test] + fn test_parse_dcerpc_bind() { + let dcerpcbind: &[u8] = &[ + 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + ]; + let (_remainder, bind) = parse_dcerpc_bind(dcerpcbind).unwrap(); + assert_eq!(24, bind.numctxitems); + } + + #[test] + fn test_parse_bindctx_item() { + let dcerpcbind: &[u8] = &[ + 0x00, 0x00, 0x01, 0x00, 0x2c, 0xd0, 0x28, 0xda, 0x76, 0x91, 0xf6, 0x6e, 0xcb, 0x0f, + 0xbf, 0x85, 0xcd, 0x9b, 0xf6, 0x39, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5d, 0x88, 0x8a, + 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, + 0x00, 0x00, + ]; + let (_remainder, ctxitem) = parse_bindctx_item(dcerpcbind, Endianness::Little).unwrap(); + assert_eq!(0, ctxitem.ctxid); + assert_eq!(1, ctxitem.version); + assert_eq!(3, ctxitem.versionminor); + } +}