smb: implement frames

SMB1 record parsing code simplification.

Frames:

    nbss.pdu
    nbss.hdr
    nbss.data

    smb1.pdu
    smb1.hdr
    smb1.data

    smb2.pdu
    smb2.hdr
    smb2.data

    smb3.pdu
    smb3.hdr
    smb3.data

The smb* frames are created for valid SMB records.
pull/6809/head
Victor Julien 4 years ago
parent a492d94826
commit 0c9fdf8f4f

@ -36,6 +36,7 @@ use nom7::{Err, Needed};
use crate::core::*;
use crate::applayer;
use crate::applayer::*;
use crate::frames::*;
use crate::conf::*;
use crate::filecontainer::*;
use crate::applayer::{AppLayerResult, AppLayerTxData, AppLayerEvent};
@ -53,6 +54,82 @@ use crate::smb::events::*;
use crate::smb::files::*;
use crate::smb::smb2_ioctl::*;
#[repr(C)]
pub enum SMBFrameType {
NBSSPdu = 0,
NBSSHdr = 1,
NBSSData = 2,
SMB1Pdu = 3,
SMB1Hdr = 4,
SMB1Data = 5,
SMB2Pdu = 6,
SMB2Hdr = 7,
SMB2Data = 8,
SMB3Pdu = 9,
SMB3Hdr = 10,
SMB3Data = 11,
}
impl SMBFrameType {
fn from_u8(value: u8) -> Option<SMBFrameType> {
match value {
0 => Some(SMBFrameType::NBSSPdu),
1 => Some(SMBFrameType::NBSSHdr),
2 => Some(SMBFrameType::NBSSData),
3 => Some(SMBFrameType::SMB1Pdu),
4 => Some(SMBFrameType::SMB1Hdr),
5 => Some(SMBFrameType::SMB1Data),
6 => Some(SMBFrameType::SMB2Pdu),
7 => Some(SMBFrameType::SMB2Hdr),
8 => Some(SMBFrameType::SMB2Data),
9 => Some(SMBFrameType::SMB3Pdu),
10 => Some(SMBFrameType::SMB3Hdr),
11 => Some(SMBFrameType::SMB3Data),
_ => None,
}
}
}
fn smb_frame_type_string(s: &str) -> i32 {
match s {
"nbss.pdu" => SMBFrameType::NBSSPdu as i32,
"nbss.hdr" => SMBFrameType::NBSSHdr as i32,
"nbss.data" => SMBFrameType::NBSSData as i32,
"smb1.pdu" => SMBFrameType::SMB1Pdu as i32,
"smb1.hdr" => SMBFrameType::SMB1Hdr as i32,
"smb1.data" => SMBFrameType::SMB1Data as i32,
"smb2.pdu" => SMBFrameType::SMB2Pdu as i32,
"smb2.hdr" => SMBFrameType::SMB2Hdr as i32,
"smb2.data" => SMBFrameType::SMB2Data as i32,
"smb3.pdu" => SMBFrameType::SMB3Pdu as i32,
"smb3.hdr" => SMBFrameType::SMB3Hdr as i32,
"smb3.data" => SMBFrameType::SMB3Data as i32,
_ => -1,
}
}
fn smb_frame_string_type(id: u8) -> *const std::os::raw::c_char {
if let Some(s) = SMBFrameType::from_u8(id) {
let estr = match s {
SMBFrameType::NBSSPdu => "nbss.pdu\0",
SMBFrameType::NBSSHdr => "nbss.hdr\0",
SMBFrameType::NBSSData => "nbss.data\0",
SMBFrameType::SMB1Pdu => "smb1.pdu\0",
SMBFrameType::SMB1Hdr => "smb1.hdr\0",
SMBFrameType::SMB1Data => "smb1.data\0",
SMBFrameType::SMB2Pdu => "smb2.pdu\0",
SMBFrameType::SMB2Hdr => "smb2.hdr\0",
SMBFrameType::SMB2Data => "smb2.data\0",
SMBFrameType::SMB3Pdu => "smb3.pdu\0",
SMBFrameType::SMB3Hdr => "smb3.hdr\0",
SMBFrameType::SMB3Data => "smb3.data\0",
};
return estr.as_ptr() as *const std::os::raw::c_char;
}
return std::ptr::null();
}
pub const MIN_REC_SIZE: u16 = 32 + 4; // SMB hdr + nbss hdr
pub const SMB_CONFIG_DEFAULT_STREAM_DEPTH: u32 = 0;
@ -1218,8 +1295,60 @@ impl SMBState {
return consumed;
}
fn add_nbss_ts_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option<Frame>, Option<Frame>, Option<Frame>) {
let nbss_pdu = Frame::new_ts(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8);
SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu);
let nbss_hdr_frame = Frame::new_ts(flow, stream_slice, input, 4 as i64, SMBFrameType::NBSSHdr as u8);
SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame);
let nbss_data_frame = Frame::new_ts(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8);
SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame);
(nbss_pdu, nbss_hdr_frame, nbss_data_frame)
}
fn add_smb1_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
let smb_pdu = Frame::new_ts(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8);
SCLogDebug!("SMB PDU frame {:?}", smb_pdu);
smb_pdu
}
fn add_smb1_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb1_hdr = Frame::new_ts(flow, stream_slice, input, 32 as i64, SMBFrameType::SMB1Hdr as u8);
SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr);
if input.len() > 32 {
let _smb1_data = Frame::new_ts(flow, stream_slice, &input[32..], (nbss_len - 32) as i64, SMBFrameType::SMB1Data as u8);
SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data);
}
}
fn add_smb2_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
let smb_pdu = Frame::new_ts(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8);
SCLogDebug!("SMBv2 PDU frame {:?}", smb_pdu);
smb_pdu
}
fn add_smb2_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) {
let _smb2_hdr = Frame::new_ts(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8);
SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr);
if input.len() > hdr_len as usize {
let _smb2_data = Frame::new_ts(flow, stream_slice, &input[hdr_len as usize..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8);
SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data);
}
}
fn add_smb3_ts_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> Option<Frame> {
let smb_pdu = Frame::new_ts(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8);
SCLogDebug!("SMBv3 PDU frame {:?}", smb_pdu);
smb_pdu
}
fn add_smb3_ts_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb3_hdr = Frame::new_ts(flow, stream_slice, input, 52 as i64, SMBFrameType::SMB3Hdr as u8);
SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr);
if input.len() > 52 {
let _smb3_data = Frame::new_ts(flow, stream_slice, &input[52..], (nbss_len - 52) as i64, SMBFrameType::SMB3Data as u8);
SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data);
}
}
/// return bytes consumed
pub fn parse_tcp_data_ts_partial<'b>(&mut self, input: &'b[u8]) -> usize
pub fn parse_tcp_data_ts_partial<'b>(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &'b[u8]) -> usize
{
SCLogDebug!("incomplete of size {}", input.len());
if input.len() < 512 {
@ -1265,6 +1394,11 @@ impl SMBState {
return 0;
}
smb1_write_request_record(self, r, SMB1_HEADER_SIZE, SMB1_COMMAND_WRITE_ANDX);
self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
let consumed = input.len() - output.len();
return consumed;
}
@ -1273,7 +1407,6 @@ impl SMBState {
}
} else if smb.version == 0xfe_u8 { // SMB2
SCLogDebug!("NBSS record {:?}", nbss_part_hdr);
SCLogDebug!("SMBv2 record");
match parse_smb2_request_record(nbss_part_hdr.data) {
Ok((_, ref smb_record)) => {
@ -1281,6 +1414,11 @@ impl SMBState {
&smb2_command_string(smb_record.command));
if smb_record.command == SMB2_COMMAND_WRITE {
smb2_write_request_record(self, smb_record);
self.add_nbss_ts_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64);
let consumed = input.len() - output.len();
SCLogDebug!("consumed {}", consumed);
return consumed;
@ -1302,9 +1440,9 @@ impl SMBState {
}
/// Parsing function, handling TCP chunks fragmentation
pub fn parse_tcp_data_ts<'b>(&mut self, i: &'b[u8]) -> AppLayerResult
pub fn parse_tcp_data_ts<'b>(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult
{
let mut cur_i = i;
let mut cur_i = stream_slice.as_slice();
let consumed = self.handle_skip(Direction::ToServer, cur_i.len() as u32);
if consumed > 0 {
if consumed > cur_i.len() as u32 {
@ -1345,7 +1483,7 @@ impl SMBState {
break;
},
_ => {
let mut consumed = i.len();
let mut consumed = stream_slice.len();
if consumed < 4 {
consumed = 0;
} else {
@ -1360,19 +1498,29 @@ impl SMBState {
while cur_i.len() > 0 { // min record size
match parse_nbss_record(cur_i) {
Ok((rem, ref nbss_hdr)) => {
SCLogDebug!("nbss frame offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len());
let (_, _, nbss_data_frame) = self.add_nbss_ts_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64);
if nbss_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
// we have the full records size worth of data,
// let's parse it
match parse_smb_version(nbss_hdr.data) {
Ok((_, ref smb)) => {
SCLogDebug!("SMB {:?}", smb);
if smb.version == 0xff_u8 { // SMB1
SCLogDebug!("SMBv1 record");
match parse_smb_record(nbss_hdr.data) {
Ok((_, ref smb_record)) => {
self.add_smb1_ts_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
self.add_smb1_ts_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
smb1_request_record(self, smb_record);
},
_ => {
if let Some(frame) = nbss_data_frame {
frame.add_event(flow, 0, SMBEvent::MalformedData as u8);
}
self.set_event(SMBEvent::MalformedData);
return AppLayerResult::err();
},
@ -1383,26 +1531,38 @@ impl SMBState {
SCLogDebug!("SMBv2 record");
match parse_smb2_request_record(nbss_data) {
Ok((nbss_data_rem, ref smb_record)) => {
let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
self.add_smb2_ts_pdu_frame(flow, stream_slice, nbss_data, record_len);
self.add_smb2_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64);
SCLogDebug!("nbss_data_rem {}", nbss_data_rem.len());
smb2_request_record(self, smb_record);
nbss_data = nbss_data_rem;
},
_ => {
if let Some(frame) = nbss_data_frame {
frame.add_event(flow, 0, SMBEvent::MalformedData as u8);
}
self.set_event(SMBEvent::MalformedData);
return AppLayerResult::err();
},
}
}
} else if smb.version == 0xfd_u8 { // SMB3 transform
let mut nbss_data = nbss_hdr.data;
while nbss_data.len() > 0 {
SCLogDebug!("SMBv3 transform record");
match parse_smb3_transform_record(nbss_data) {
Ok((nbss_data_rem, ref _smb3_record)) => {
let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
self.add_smb3_ts_pdu_frame(flow, stream_slice, nbss_data, record_len);
self.add_smb3_ts_hdr_data_frames(flow, stream_slice, nbss_data, record_len);
nbss_data = nbss_data_rem;
},
_ => {
if let Some(frame) = nbss_data_frame {
frame.add_event(flow, 0, SMBEvent::MalformedData as u8);
}
self.set_event(SMBEvent::MalformedData);
return AppLayerResult::err();
},
@ -1425,15 +1585,15 @@ impl SMBState {
let n = usize::from(n) + cur_i.len();
// 512 is the minimum for parse_tcp_data_ts_partial
if n >= 512 && cur_i.len() < 512 {
let total_consumed = i.len() - cur_i.len();
return AppLayerResult::incomplete(total_consumed as u32, 512);
let total_consumed = stream_slice.offset_from(cur_i);
return AppLayerResult::incomplete(total_consumed, 512);
}
let consumed = self.parse_tcp_data_ts_partial(cur_i);
let consumed = self.parse_tcp_data_ts_partial(flow, stream_slice, cur_i);
if consumed == 0 {
// if we consumed none we will buffer the entire record
let total_consumed = i.len() - cur_i.len();
let total_consumed = stream_slice.offset_from(cur_i);
SCLogDebug!("setting consumed {} need {} needed {:?} total input {}",
total_consumed, n, needed, i.len());
total_consumed, n, needed, stream_slice.len());
let need = n;
return AppLayerResult::incomplete(total_consumed as u32, need as u32);
}
@ -1461,8 +1621,58 @@ impl SMBState {
AppLayerResult::ok()
}
fn add_nbss_tc_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) -> (Option<Frame>, Option<Frame>, Option<Frame>) {
let nbss_pdu = Frame::new_tc(flow, stream_slice, input, nbss_len + 4, SMBFrameType::NBSSPdu as u8);
SCLogDebug!("NBSS PDU frame {:?}", nbss_pdu);
let nbss_hdr_frame = Frame::new_tc(flow, stream_slice, input, 4 as i64, SMBFrameType::NBSSHdr as u8);
SCLogDebug!("NBSS HDR frame {:?}", nbss_hdr_frame);
let nbss_data_frame = Frame::new_tc(flow, stream_slice, &input[4..], nbss_len, SMBFrameType::NBSSData as u8);
SCLogDebug!("NBSS DATA frame {:?}", nbss_data_frame);
(nbss_pdu, nbss_hdr_frame, nbss_data_frame)
}
fn add_smb1_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb_pdu = Frame::new_tc(flow, stream_slice, input, nbss_len, SMBFrameType::SMB1Pdu as u8);
SCLogDebug!("SMB PDU frame {:?}", _smb_pdu);
}
fn add_smb1_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb1_hdr = Frame::new_tc(flow, stream_slice, input, SMB1_HEADER_SIZE as i64, SMBFrameType::SMB1Hdr as u8);
SCLogDebug!("SMBv1 HDR frame {:?}", _smb1_hdr);
if input.len() > SMB1_HEADER_SIZE {
let _smb1_data = Frame::new_tc(flow, stream_slice, &input[SMB1_HEADER_SIZE..], (nbss_len - SMB1_HEADER_SIZE as i64) as i64,
SMBFrameType::SMB1Data as u8);
SCLogDebug!("SMBv1 DATA frame {:?}", _smb1_data);
}
}
fn add_smb2_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb_pdu = Frame::new_tc(flow, stream_slice, input, nbss_len, SMBFrameType::SMB2Pdu as u8);
SCLogDebug!("SMBv2 PDU frame {:?}", _smb_pdu);
}
fn add_smb2_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64, hdr_len: i64) {
let _smb2_hdr = Frame::new_tc(flow, stream_slice, input, hdr_len, SMBFrameType::SMB2Hdr as u8);
SCLogDebug!("SMBv2 HDR frame {:?}", _smb2_hdr);
if input.len() > hdr_len as usize {
let _smb2_data = Frame::new_tc(flow, stream_slice, &input[hdr_len as usize ..], nbss_len - hdr_len, SMBFrameType::SMB2Data as u8);
SCLogDebug!("SMBv2 DATA frame {:?}", _smb2_data);
}
}
fn add_smb3_tc_pdu_frame(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb_pdu = Frame::new_tc(flow, stream_slice, input, nbss_len, SMBFrameType::SMB3Pdu as u8);
SCLogDebug!("SMBv3 PDU frame {:?}", _smb_pdu);
}
fn add_smb3_tc_hdr_data_frames(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &[u8], nbss_len: i64) {
let _smb3_hdr = Frame::new_tc(flow, stream_slice, input, 52 as i64, SMBFrameType::SMB3Hdr as u8);
SCLogDebug!("SMBv3 HDR frame {:?}", _smb3_hdr);
if input.len() > 52 {
let _smb3_data = Frame::new_tc(flow, stream_slice, &input[52..], (nbss_len - 52) as i64, SMBFrameType::SMB3Data as u8);
SCLogDebug!("SMBv3 DATA frame {:?}", _smb3_data);
}
}
/// return bytes consumed
pub fn parse_tcp_data_tc_partial<'b>(&mut self, input: &'b[u8]) -> usize
pub fn parse_tcp_data_tc_partial<'b>(&mut self, flow: *const Flow, stream_slice: &StreamSlice, input: &'b[u8]) -> usize
{
SCLogDebug!("incomplete of size {}", input.len());
if input.len() < 512 {
@ -1484,67 +1694,67 @@ impl SMBState {
return 0;
}
match parse_nbss_record_partial(input) {
Ok((output, ref nbss_part_hdr)) => {
SCLogDebug!("parse_nbss_record_partial ok, output len {}", output.len());
if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
match parse_smb_version(nbss_part_hdr.data) {
Ok((_, ref smb)) => {
SCLogDebug!("SMB {:?}", smb);
if smb.version == 255u8 { // SMB1
SCLogDebug!("SMBv1 record");
match parse_smb_record(nbss_part_hdr.data) {
Ok((_, ref r)) => {
SCLogDebug!("SMB1: partial record {}",
r.command);
if r.command == SMB1_COMMAND_READ_ANDX {
let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE,
r.ssn_id as u64, r.tree_id as u32, 0);
let is_pipe = match self.ssn2tree_map.get(&tree_key) {
Some(n) => n.is_pipe,
None => false,
};
if is_pipe {
return 0;
}
smb1_read_response_record(self, r, SMB1_HEADER_SIZE);
let consumed = input.len() - output.len();
return consumed;
}
},
_ => { },
}
} else if smb.version == 254u8 { // SMB2
SCLogDebug!("SMBv2 record");
match parse_smb2_response_record(nbss_part_hdr.data) {
Ok((_, ref smb_record)) => {
SCLogDebug!("SMB2: partial record {}",
&smb2_command_string(smb_record.command));
if smb_record.command == SMB2_COMMAND_READ {
smb2_read_response_record(self, smb_record);
let consumed = input.len() - output.len();
return consumed;
}
},
_ => { },
if let Ok((output, ref nbss_part_hdr)) = parse_nbss_record_partial(input) {
SCLogDebug!("parse_nbss_record_partial ok, output len {}", output.len());
if nbss_part_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
if let Ok((_, ref smb)) = parse_smb_version(nbss_part_hdr.data) {
SCLogDebug!("SMB {:?}", smb);
if smb.version == 255u8 { // SMB1
SCLogDebug!("SMBv1 record");
if let Ok((_, ref r)) = parse_smb_record(nbss_part_hdr.data) {
SCLogDebug!("SMB1: partial record {}",
r.command);
if r.command == SMB1_COMMAND_READ_ANDX {
let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE,
r.ssn_id as u64, r.tree_id as u32, 0);
let is_pipe = match self.ssn2tree_map.get(&tree_key) {
Some(n) => n.is_pipe,
None => false,
};
if is_pipe {
return 0;
}
// create NBSS frames here so we don't get double frames
// when we don't consume the data now.
self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
smb1_read_response_record(self, r, SMB1_HEADER_SIZE);
let consumed = input.len() - output.len();
return consumed;
}
// no SMB3 here yet, will buffer full records
},
_ => { },
}
} else if smb.version == 254u8 { // SMB2
SCLogDebug!("SMBv2 record");
if let Ok((_, ref smb_record)) = parse_smb2_response_record(nbss_part_hdr.data) {
SCLogDebug!("SMB2: partial record {}",
&smb2_command_string(smb_record.command));
if smb_record.command == SMB2_COMMAND_READ {
// create NBSS frames here so we don't get double frames
// when we don't consume the data now.
self.add_nbss_tc_frames(flow, stream_slice, input, nbss_part_hdr.length as i64);
self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64);
self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_part_hdr.data, nbss_part_hdr.length as i64, smb_record.header_len as i64);
smb2_read_response_record(self, smb_record);
let consumed = input.len() - output.len();
return consumed;
}
}
}
// no SMB3 here yet, will buffer full records
}
},
_ => { },
}
}
return 0;
}
/// Parsing function, handling TCP chunks fragmentation
pub fn parse_tcp_data_tc<'b>(&mut self, i: &'b[u8]) -> AppLayerResult
pub fn parse_tcp_data_tc<'b>(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult
{
let mut cur_i = i;
let mut cur_i = stream_slice.as_slice();
let consumed = self.handle_skip(Direction::ToClient, cur_i.len() as u32);
if consumed > 0 {
if consumed > cur_i.len() as u32 {
@ -1585,7 +1795,7 @@ impl SMBState {
break;
},
_ => {
let mut consumed = i.len();
let mut consumed = stream_slice.len();
if consumed < 4 {
consumed = 0;
} else {
@ -1600,6 +1810,10 @@ impl SMBState {
while cur_i.len() > 0 { // min record size
match parse_nbss_record(cur_i) {
Ok((rem, ref nbss_hdr)) => {
SCLogDebug!("nbss record offset {} len {}", stream_slice.offset_from(cur_i), cur_i.len() - rem.len());
self.add_nbss_tc_frames(flow, stream_slice, cur_i, nbss_hdr.length as i64);
SCLogDebug!("nbss frames added");
if nbss_hdr.message_type == NBSS_MSGTYPE_SESSION_MESSAGE {
// we have the full records size worth of data,
// let's parse it
@ -1610,6 +1824,8 @@ impl SMBState {
SCLogDebug!("SMBv1 record");
match parse_smb_record(nbss_hdr.data) {
Ok((_, ref smb_record)) => {
self.add_smb1_tc_pdu_frame(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
self.add_smb1_tc_hdr_data_frames(flow, stream_slice, nbss_hdr.data, nbss_hdr.length as i64);
smb1_response_record(self, smb_record);
},
_ => {
@ -1623,6 +1839,9 @@ impl SMBState {
SCLogDebug!("SMBv2 record");
match parse_smb2_response_record(nbss_data) {
Ok((nbss_data_rem, ref smb_record)) => {
let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
self.add_smb2_tc_pdu_frame(flow, stream_slice, nbss_data, record_len);
self.add_smb2_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len, smb_record.header_len as i64);
smb2_response_record(self, smb_record);
nbss_data = nbss_data_rem;
},
@ -1638,6 +1857,9 @@ impl SMBState {
SCLogDebug!("SMBv3 transform record");
match parse_smb3_transform_record(nbss_data) {
Ok((nbss_data_rem, ref _smb3_record)) => {
let record_len = (nbss_data.len() - nbss_data_rem.len()) as i64;
self.add_smb3_tc_pdu_frame(flow, stream_slice, nbss_data, record_len);
self.add_smb3_tc_hdr_data_frames(flow, stream_slice, nbss_data, record_len);
nbss_data = nbss_data_rem;
},
_ => {
@ -1668,15 +1890,15 @@ impl SMBState {
let n = usize::from(n) + cur_i.len();
// 512 is the minimum for parse_tcp_data_tc_partial
if n >= 512 && cur_i.len() < 512 {
let total_consumed = i.len() - cur_i.len();
return AppLayerResult::incomplete(total_consumed as u32, 512);
let total_consumed = stream_slice.offset_from(cur_i);
return AppLayerResult::incomplete(total_consumed, 512);
}
let consumed = self.parse_tcp_data_tc_partial(cur_i);
let consumed = self.parse_tcp_data_tc_partial(flow, stream_slice, cur_i);
if consumed == 0 {
// if we consumed none we will buffer the entire record
let total_consumed = i.len() - cur_i.len();
let total_consumed = stream_slice.offset_from(cur_i);
SCLogDebug!("setting consumed {} need {} needed {:?} total input {}",
total_consumed, n, needed, i.len());
total_consumed, n, needed, stream_slice.len());
let need = n;
return AppLayerResult::incomplete(total_consumed as u32, need as u32);
}
@ -1815,7 +2037,7 @@ pub unsafe extern "C" fn rs_smb_parse_request_tcp(flow: *const Flow,
}
state.update_ts(flow.get_last_time().as_secs());
state.parse_tcp_data_ts(stream_slice.as_slice())
state.parse_tcp_data_ts(flow, &stream_slice)
}
#[no_mangle]
@ -1845,7 +2067,6 @@ pub unsafe extern "C" fn rs_smb_parse_response_tcp(flow: *const Flow,
if stream_slice.is_gap() {
return rs_smb_parse_response_tcp_gap(state, stream_slice.gap_size());
}
SCLogDebug!("parsing {} bytes of response data", stream_slice.len());
/* START with MISTREAM set: record might be starting the middle. */
if stream_slice.flags() & (STREAM_START|STREAM_MIDSTREAM) == (STREAM_START|STREAM_MIDSTREAM) {
@ -1853,7 +2074,7 @@ pub unsafe extern "C" fn rs_smb_parse_response_tcp(flow: *const Flow,
}
state.update_ts(flow.get_last_time().as_secs());
state.parse_tcp_data_tc(stream_slice.as_slice())
state.parse_tcp_data_tc(flow, &stream_slice)
}
#[no_mangle]
@ -2100,6 +2321,18 @@ pub unsafe extern "C" fn smb3_probe_tcp(f: *const Flow, dir: u8, input: *const u
return ALPROTO_SMB;
}
pub unsafe extern "C" fn smb_frames_get_frame_id_by_name(name: *const std::os::raw::c_char) -> std::os::raw::c_int {
if let Ok(s) = std::ffi::CStr::from_ptr(name).to_str() {
smb_frame_type_string(s) as std::os::raw::c_int
} else {
-1
}
}
pub unsafe extern "C" fn smb_frames_get_frame_by_id(id: u8) -> *const std::os::raw::c_char {
smb_frame_string_type(id)
}
fn register_pattern_probe() -> i8 {
let mut r = 0;
unsafe {
@ -2168,8 +2401,8 @@ pub unsafe extern "C" fn rs_smb_register_parser() {
apply_tx_config: None,
flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS,
truncate: Some(rs_smb_state_truncate),
get_frame_id_by_name: None,
get_frame_name_by_id: None,
get_frame_id_by_name: Some(smb_frames_get_frame_id_by_name),
get_frame_name_by_id: Some(smb_frames_get_frame_by_id),
};
let ip_proto_str = CString::new("tcp").unwrap();

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Open Information Security Foundation
/* Copyright (C) 2018-2021 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
@ -198,7 +198,7 @@ fn smb1_command_is_andx(c: u8) -> bool {
}
}
fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: u8, andx_offset: &mut usize) -> u32 {
fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: u8, andx_offset: &mut usize) {
let mut events : Vec<SMBEvent> = Vec::new();
let mut no_response_expected = false;
@ -593,7 +593,6 @@ fn smb1_request_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command:
}
}
}
return 0;
}
pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
@ -602,9 +601,8 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
let mut andx_offset = SMB1_HEADER_SIZE;
let mut command = r.command;
loop {
if smb1_request_record_one(state, r, command, &mut andx_offset) != 0 {
break;
}
smb1_request_record_one(state, r, command, &mut andx_offset);
// continue for next andx command if any
if smb1_command_is_andx(command) {
if let Ok((_, andx_hdr)) = smb1_parse_andx_header(&r.data[andx_offset-SMB1_HEADER_SIZE..]) {
@ -623,7 +621,7 @@ pub fn smb1_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
0
}
fn smb1_response_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: u8, andx_offset: &mut usize) -> u32 {
fn smb1_response_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command: u8, andx_offset: &mut usize) {
SCLogDebug!("record: command {} status {} -> {:?}", r.command, r.nt_status, r);
let key_ssn_id = r.ssn_id;
@ -693,7 +691,7 @@ fn smb1_response_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command
},
None => { },
}
return 0;
return;
}
match parse_smb_connect_tree_andx_response_record(&r.data[*andx_offset-SMB1_HEADER_SIZE..]) {
@ -835,17 +833,13 @@ fn smb1_response_record_one<'b>(state: &mut SMBState, r: &SmbRecord<'b>, command
} else {
SCLogDebug!("have tx for cmd {}", command);
}
return 0;
}
pub fn smb1_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>) -> u32 {
let mut andx_offset = SMB1_HEADER_SIZE;
let mut command = r.command;
loop {
if smb1_response_record_one(state, r, command, &mut andx_offset) != 0 {
break;
}
smb1_response_record_one(state, r, command, &mut andx_offset);
// continue for next andx command if any
if smb1_command_is_andx(command) {

@ -54,6 +54,7 @@ pub fn parse_smb2_record_direction(i: &[u8]) -> IResult<&[u8], Smb2RecordDir> {
#[derive(Debug,PartialEq)]
pub struct Smb2Record<'a> {
pub direction: u8, // 0 req, 1 res
pub header_len: u16,
pub nt_status: u32,
pub command: u16,
pub message_id: u64,
@ -104,6 +105,7 @@ pub fn parse_smb2_request_record(i: &[u8]) -> IResult<&[u8], Smb2Record> {
};
let record = Smb2Record {
direction: flags.7,
header_len: hlen,
nt_status: 0,
command,
message_id,
@ -558,6 +560,7 @@ pub fn parse_smb2_response_record(i: &[u8]) -> IResult<&[u8], Smb2Record> {
};
let record = Smb2Record {
direction: flags.7,
header_len: hlen,
nt_status,
message_id,
tree_id: tree_id.unwrap_or(0),

Loading…
Cancel
Save