]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
smb: implement frames
authorVictor Julien <vjulien@oisf.net>
Mon, 6 Dec 2021 10:35:23 +0000 (11:35 +0100)
committerVictor Julien <vjulien@oisf.net>
Tue, 18 Jan 2022 11:21:53 +0000 (12:21 +0100)
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.

rust/src/smb/smb.rs
rust/src/smb/smb1.rs
rust/src/smb/smb2_records.rs

index 6336ce4384a08f8be6eed96fe2ddda31cf985698..9a9a59823a753c46c7ce579acc7a2945af66cfa8 100644 (file)
@@ -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();
index ec4149d3b2b3f7048db244eddd76c6b71ff0f17c..f503401009f3cd3ec110d54bc8f6a693080c4a98 100644 (file)
@@ -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) {
index c892faad477fcb60a1037c61f417bafbb2e1ad2c..5e5f1da44862e87e7a2e85b1077329ac5ed51530 100644 (file)
@@ -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),