dcerpc: support multiple PDU in one parser call

Ticket: 7254

With TCP, we receive a stream of data, which may contain multiple
PDUs in one call
pull/15046/head
Philippe Antoine 2 months ago committed by Victor Julien
parent db51314478
commit 2c2a3c800f

@ -802,7 +802,6 @@ impl DCERPCState {
pub fn handle_input_data(
&mut self, stream_slice: StreamSlice, direction: Direction,
) -> AppLayerResult {
let retval;
let mut cur_i = stream_slice.as_slice();
let mut consumed = 0u32;
@ -846,156 +845,166 @@ impl DCERPCState {
}
// Check if header data was complete. In case of EoF or incomplete data, wait for more
// data else return error
let hdr = match parser::parse_dcerpc_header(cur_i) {
Ok((_leftover_bytes, header)) => {
if header.rpc_vers != 5
|| (header.rpc_vers_minor != 0 && header.rpc_vers_minor != 1)
{
SCLogDebug!(
while !cur_i.is_empty() {
let hdr = match parser::parse_dcerpc_header(cur_i) {
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 AppLayerResult::err();
}
header
}
Err(Err::Incomplete(_)) => {
// Insufficient data.
SCLogDebug!("Insufficient data while parsing DCERPC header");
return AppLayerResult::incomplete(consumed, DCERPC_HDR_LEN as u32);
}
Err(Err::Error(Error {
code: ErrorKind::Eof,
..
})) => {
SCLogDebug!("EoF reached while parsing DCERPC header");
return AppLayerResult::incomplete(consumed, DCERPC_HDR_LEN as u32);
}
Err(_) => {
// Error, probably malformed data.
SCLogDebug!("An error occurred while parsing DCERPC header");
return AppLayerResult::err();
}
header
}
Err(Err::Incomplete(_)) => {
// Insufficient data.
SCLogDebug!("Insufficient data while parsing DCERPC header");
return AppLayerResult::incomplete(consumed, DCERPC_HDR_LEN as u32);
}
Err(Err::Error(Error {
code: ErrorKind::Eof,
..
})) => {
SCLogDebug!("EoF reached while parsing DCERPC header");
return AppLayerResult::incomplete(consumed, DCERPC_HDR_LEN as u32);
}
Err(_) => {
// Error, probably malformed data.
SCLogDebug!("An error occurred while parsing DCERPC header");
return AppLayerResult::err();
}
};
let parsed = DCERPC_HDR_LEN;
let fraglen = hdr.frag_length;
match fraglen.cmp(&parsed) {
cmp::Ordering::Less => {
// fragment length should at least be header length
SCLogDebug!("Erroneous fragment length");
return AppLayerResult::err();
}
cmp::Ordering::Equal => {
// input only consists of the header and that was consumed, so, return early
return AppLayerResult::ok();
};
let parsed = DCERPC_HDR_LEN;
let fraglen = hdr.frag_length;
match fraglen.cmp(&parsed) {
cmp::Ordering::Less => {
// fragment length should at least be header length
SCLogDebug!("Erroneous fragment length");
return AppLayerResult::err();
}
cmp::Ordering::Equal => {
// input only consists of the header and that was consumed, so, return early
cur_i = &cur_i[fraglen as usize..];
consumed += fraglen as u32;
continue;
}
cmp::Ordering::Greater => {}
}
cmp::Ordering::Greater => {}
}
if cur_i.len() < fraglen as usize {
SCLogDebug!("Possibly fragmented data, waiting for more..");
return AppLayerResult::incomplete(consumed, fraglen.into());
}
if cur_i.len() < fraglen as usize {
SCLogDebug!("Possibly fragmented data, waiting for more..");
return AppLayerResult::incomplete(consumed, fraglen.into());
}
let hdrtype = hdr.hdrtype;
let hdrtype = hdr.hdrtype;
let _hdr = Frame::new(
flow,
&stream_slice,
cur_i,
parsed as i64,
DCERPCFrameType::Hdr as u8,
None,
);
let _pdu = Frame::new(
flow,
&stream_slice,
cur_i,
fraglen as i64,
DCERPCFrameType::Pdu as u8,
None,
);
if fraglen >= DCERPC_HDR_LEN && cur_i.len() > DCERPC_HDR_LEN as usize {
let _data = Frame::new(
let _hdr = Frame::new(
flow,
&stream_slice,
&cur_i[DCERPC_HDR_LEN as usize..],
(fraglen - DCERPC_HDR_LEN) as i64,
DCERPCFrameType::Data as u8,
cur_i,
parsed as i64,
DCERPCFrameType::Hdr as u8,
None,
);
}
let current_call_id = hdr.call_id;
debug_validate_bug_on!(parsed > fraglen);
match hdrtype {
DCERPC_TYPE_BIND | DCERPC_TYPE_ALTER_CONTEXT => {
retval = self.process_bind_pdu(&cur_i[parsed as usize..fraglen as usize], &hdr);
if retval == -1 {
return AppLayerResult::err();
}
}
DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => {
retval = self.process_bindack_pdu(&cur_i[parsed as usize..fraglen as usize]);
if retval == -1 {
return AppLayerResult::err();
}
let tx = if let Some(tx) =
self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype)
{
tx.resp_cmd = hdrtype;
tx
} else {
let mut tx = self.create_tx(&hdr);
tx.resp_cmd = hdrtype;
self.transactions.push_back(tx);
self.transactions.back_mut().unwrap()
};
tx.resp_done = true;
tx.frag_cnt_tc = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_inspection(
flow,
Direction::ToClient as i32,
);
}
let _pdu = Frame::new(
flow,
&stream_slice,
cur_i,
fraglen as i64,
DCERPCFrameType::Pdu as u8,
None,
);
if fraglen >= DCERPC_HDR_LEN && cur_i.len() > DCERPC_HDR_LEN as usize {
let _data = Frame::new(
flow,
&stream_slice,
&cur_i[DCERPC_HDR_LEN as usize..],
(fraglen - DCERPC_HDR_LEN) as i64,
DCERPCFrameType::Data as u8,
None,
);
}
DCERPC_TYPE_REQUEST => {
retval = self.process_request_pdu(&cur_i[parsed as usize..fraglen as usize], &hdr);
if retval < 0 {
return AppLayerResult::err();
let current_call_id = hdr.call_id;
debug_validate_bug_on!(parsed > fraglen);
match hdrtype {
DCERPC_TYPE_BIND | DCERPC_TYPE_ALTER_CONTEXT => {
let retval =
self.process_bind_pdu(&cur_i[parsed as usize..fraglen as usize], &hdr);
if retval == -1 {
return AppLayerResult::err();
}
}
// In case the response came first, the transaction would complete later when
// the corresponding request also comes through
}
DCERPC_TYPE_RESPONSE => {
let transaction =
self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype);
match transaction {
Some(tx) => {
tx.resp_cmd = hdrtype;
DCERPC_TYPE_BINDACK | DCERPC_TYPE_ALTER_CONTEXT_RESP => {
let retval =
self.process_bindack_pdu(&cur_i[parsed as usize..fraglen as usize]);
if retval == -1 {
return AppLayerResult::err();
}
None => {
let tx = if let Some(tx) =
self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype)
{
tx.resp_cmd = hdrtype;
tx
} else {
let mut tx = self.create_tx(&hdr);
tx.resp_cmd = hdrtype;
self.transactions.push_back(tx);
self.transactions.back_mut().unwrap()
};
tx.resp_done = true;
tx.frag_cnt_tc = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_inspection(
flow,
Direction::ToClient as i32,
);
}
};
retval = self.handle_common_stub(
&cur_i[parsed as usize..fraglen as usize],
0,
Direction::ToClient,
&hdr,
);
if retval < 0 {
return AppLayerResult::err();
}
DCERPC_TYPE_REQUEST => {
let retval =
self.process_request_pdu(&cur_i[parsed as usize..fraglen as usize], &hdr);
if retval < 0 {
return AppLayerResult::err();
}
// In case the response came first, the transaction would complete later when
// the corresponding request also comes through
}
DCERPC_TYPE_RESPONSE => {
let transaction =
self.get_tx_by_call_id(current_call_id, Direction::ToClient, hdrtype);
match transaction {
Some(tx) => {
tx.resp_cmd = hdrtype;
}
None => {
let mut tx = self.create_tx(&hdr);
tx.resp_cmd = hdrtype;
self.transactions.push_back(tx);
}
};
let retval = self.handle_common_stub(
&cur_i[parsed as usize..fraglen as usize],
0,
Direction::ToClient,
&hdr,
);
if retval < 0 {
return AppLayerResult::err();
}
}
_ => {
SCLogDebug!("Unrecognized packet type: {:?}", hdrtype);
// skip unrecognized packet types such as AUTH3
}
}
_ => {
SCLogDebug!("Unrecognized packet type: {:?}", hdrtype);
// skip unrecognized packet types such as AUTH3
}
consumed += fraglen as u32;
cur_i = &cur_i[fraglen as usize..];
}
self.post_gap_housekeeping(direction);

Loading…
Cancel
Save