ReadRequestTooLarge = 10,
/// READ response bigger than `max_read_size`
ReadResponseTooLarge = 11,
+ ReadResponseQueueSizeExceeded = 12,
+ ReadResponseQueueCntExceeded = 13,
/// WRITE request for more than `max_write_size`
- WriteRequestTooLarge = 12,
+ WriteRequestTooLarge = 14,
+ WriteQueueSizeExceeded = 15,
+ WriteQueueCntExceeded = 16,
}
impl SMBEvent {
9 => Some(SMBEvent::ResponseToServer),
10 => Some(SMBEvent::ReadRequestTooLarge),
11 => Some(SMBEvent::ReadResponseTooLarge),
- 12 => Some(SMBEvent::WriteRequestTooLarge),
+ 12 => Some(SMBEvent::ReadResponseQueueSizeExceeded),
+ 13 => Some(SMBEvent::ReadResponseQueueCntExceeded),
+ 14 => Some(SMBEvent::WriteRequestTooLarge),
+ 15 => Some(SMBEvent::WriteQueueSizeExceeded),
+ 16 => Some(SMBEvent::WriteQueueCntExceeded),
_ => None,
}
}
pub fn smb_str_to_event(instr: &str) -> i32 {
SCLogDebug!("checking {}", instr);
match instr {
- "internal_error" => SMBEvent::InternalError as i32,
- "malformed_data" => SMBEvent::MalformedData as i32,
- "record_overflow" => SMBEvent::RecordOverflow as i32,
- "malformed_ntlmssp_request" => SMBEvent::MalformedNtlmsspRequest as i32,
- "malformed_ntlmssp_response" => SMBEvent::MalformedNtlmsspResponse as i32,
- "duplicate_negotiate" => SMBEvent::DuplicateNegotiate as i32,
- "negotiate_malformed_dialects" => SMBEvent::NegotiateMalformedDialects as i32,
- "file_overlap" => SMBEvent::FileOverlap as i32,
- "request_to_client" => SMBEvent::RequestToClient as i32,
- "response_to_server" => SMBEvent::ResponseToServer as i32,
- "read_request_too_large" => SMBEvent::ReadRequestTooLarge as i32,
- "read_response_too_large" => SMBEvent::ReadResponseTooLarge as i32,
- "write_request_too_large" => SMBEvent::WriteRequestTooLarge as i32,
+ "internal_error" => SMBEvent::InternalError as i32,
+ "malformed_data" => SMBEvent::MalformedData as i32,
+ "record_overflow" => SMBEvent::RecordOverflow as i32,
+ "malformed_ntlmssp_request" => SMBEvent::MalformedNtlmsspRequest as i32,
+ "malformed_ntlmssp_response" => SMBEvent::MalformedNtlmsspResponse as i32,
+ "duplicate_negotiate" => SMBEvent::DuplicateNegotiate as i32,
+ "negotiate_malformed_dialects" => SMBEvent::NegotiateMalformedDialects as i32,
+ "file_overlap" => SMBEvent::FileOverlap as i32,
+ "request_to_client" => SMBEvent::RequestToClient as i32,
+ "response_to_server" => SMBEvent::ResponseToServer as i32,
+ "read_request_too_large" => SMBEvent::ReadRequestTooLarge as i32,
+ "read_response_too_large" => SMBEvent::ReadResponseTooLarge as i32,
+ "read_queue_size_too_large" => SMBEvent::ReadResponseQueueSizeExceeded as i32,
+ "read_queue_cnt_too_large" => SMBEvent::ReadResponseQueueCntExceeded as i32,
+ "write_request_too_large" => SMBEvent::WriteRequestTooLarge as i32,
+ "write_queue_size_too_large" => SMBEvent::WriteQueueSizeExceeded as i32,
+ "write_queue_cnt_too_large" => SMBEvent::WriteQueueCntExceeded as i32,
_ => -1,
}
}
pub fn smb2_read_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
{
+ let max_queue_size = unsafe { SMB_CFG_MAX_READ_QUEUE_SIZE };
+ let max_queue_cnt = unsafe { SMB_CFG_MAX_READ_QUEUE_CNT };
+
smb2_read_response_record_generic(state, r);
match parse_smb2_response_read(r.data) {
let mut set_event_fileoverlap = false;
// look up existing tracker and if we have it update it
- let found = match state.get_file_tx_by_fuid(&file_guid, STREAM_TOCLIENT) {
- Some((tx, files, flags)) => {
- if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
- let file_id : u32 = tx.id as u32;
- if offset < tdf.file_tracker.tracked {
- set_event_fileoverlap = true;
- }
+
+ let mut found = false;
+ let mut skip = None;
+ let mut event= None;
+ if let Some((tx, files, flags)) = state.get_file_tx_by_fuid(&file_guid, STREAM_TOCLIENT) {
+ if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
+ let file_id : u32 = tx.id as u32;
+ if offset < tdf.file_tracker.tracked {
+ set_event_fileoverlap = true;
+ }
+ if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + rd.len as u64 > max_queue_size.into() {
+ event = Some(SMBEvent::ReadResponseQueueCntExceeded);
+ skip = Some((rd.len, rd.data.len()));
+ } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize {
+ event = Some(SMBEvent::ReadResponseQueueCntExceeded);
+ skip = Some((rd.len, rd.data.len()));
+ } else {
filetracker_newchunk(&mut tdf.file_tracker, files, flags,
&tdf.file_name, rd.data, offset,
rd.len, false, &file_id);
}
- true
- },
- None => { false },
- };
+ }
+ found = true;
+ }
+ if let Some((rd_len, rd_data_len)) = skip {
+ state.set_skip(STREAM_TOCLIENT, rd_len, rd_data_len as u32);
+ }
+ if let Some(event) = event {
+ state.set_event(event);
+ }
+
SCLogDebug!("existing file tx? {}", found);
if !found {
let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE);
}
}
+ let mut event = None;
+ let mut skip = None;
if is_pipe && is_dcerpc {
SCLogDebug!("SMBv2 DCERPC read");
let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER);
smb_read_dcerpc_record(state, vercmd, hdr, &file_guid, rd.data);
} else if is_pipe {
SCLogDebug!("non-DCERPC pipe");
- state.set_skip(STREAM_TOCLIENT, rd.len, rd.data.len() as u32);
+ skip = Some((rd.len, rd.data.len()));
} else {
let file_name = match state.guid2name_map.get(&file_guid) {
- Some(n) => { n.to_vec() },
- None => { b"<unknown>".to_vec() },
+ Some(n) => { n.to_vec() }
+ None => { b"<unknown>".to_vec() }
};
let (tx, files, flags) = state.new_file_tx(&file_guid, &file_name, STREAM_TOCLIENT);
+
+ tx.vercmd.set_smb2_cmd(SMB2_COMMAND_READ);
+ tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER,
+ r.session_id, r.tree_id, 0); // TODO move into new_file_tx
+
if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
+ tdf.share_name = share_name;
let file_id : u32 = tx.id as u32;
if offset < tdf.file_tracker.tracked {
set_event_fileoverlap = true;
}
- filetracker_newchunk(&mut tdf.file_tracker, files, flags,
- &file_name, rd.data, offset,
- rd.len, false, &file_id);
- tdf.share_name = share_name;
+ if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + rd.len as u64 > max_queue_size.into() {
+ event = Some(SMBEvent::ReadResponseQueueSizeExceeded);
+ skip = Some((rd.len, rd.data.len()));
+ } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize {
+ event = Some(SMBEvent::ReadResponseQueueCntExceeded);
+ skip = Some((rd.len, rd.data.len()));
+ } else {
+ filetracker_newchunk(&mut tdf.file_tracker, files, flags,
+ &file_name, rd.data, offset,
+ rd.len, false, &file_id);
+ }
}
- tx.vercmd.set_smb2_cmd(SMB2_COMMAND_READ);
- tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER,
- r.session_id, r.tree_id, 0); // TODO move into new_file_tx
+ }
+ if let Some(event) = event {
+ state.set_event(event);
+ }
+ if let Some((rd_len, rd_data_len)) = skip {
+ state.set_skip(STREAM_TOCLIENT, rd_len, rd_data_len as u32);
}
}
pub fn smb2_write_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
{
+ let max_queue_size = unsafe { SMB_CFG_MAX_WRITE_QUEUE_SIZE };
+ let max_queue_cnt = unsafe { SMB_CFG_MAX_WRITE_QUEUE_CNT };
+
SCLogDebug!("SMBv2/WRITE: request record");
if smb2_create_new_tx(r.command) {
let tx_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX);
};
let mut set_event_fileoverlap = false;
- let found = match state.get_file_tx_by_fuid(&file_guid, STREAM_TOSERVER) {
- Some((tx, files, flags)) => {
- if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
- let file_id : u32 = tx.id as u32;
- if wr.wr_offset < tdf.file_tracker.tracked {
- set_event_fileoverlap = true;
- }
+ let mut found = false;
+ let mut event = None;
+ let mut skip = None;
+ if let Some((tx, files, flags)) = state.get_file_tx_by_fuid(&file_guid, STREAM_TOSERVER) {
+ if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
+ let file_id : u32 = tx.id as u32;
+ if wr.wr_offset < tdf.file_tracker.tracked {
+ set_event_fileoverlap = true;
+ }
+ if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 > max_queue_size.into() {
+ event = Some(SMBEvent::WriteQueueSizeExceeded);
+ skip = Some((wr.wr_len, wr.data.len()));
+ } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize {
+ event = Some(SMBEvent::WriteQueueSizeExceeded);
+ skip = Some((wr.wr_len, wr.data.len()));
+ } else {
filetracker_newchunk(&mut tdf.file_tracker, files, flags,
&file_name, wr.data, wr.wr_offset,
wr.wr_len, false, &file_id);
}
- true
- },
- None => { false },
- };
+ }
+ found = true;
+ }
+ if let Some(event) = event {
+ state.set_event(event);
+ }
+ if let Some((len, data_len)) = skip {
+ state.set_skip(STREAM_TOSERVER, len, data_len as u32);
+ }
+
if !found {
let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE);
let (share_name, mut is_pipe) = match state.ssn2tree_map.get(&tree_key) {
SCLogDebug!("SMBv2/WRITE: not DCERPC");
}
}
+ let mut event = None;
+ let mut skip = None;
if is_pipe && is_dcerpc {
SCLogDebug!("SMBv2 DCERPC write");
let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER);
state.set_skip(STREAM_TOSERVER, wr.wr_len, wr.data.len() as u32);
} else {
let (tx, files, flags) = state.new_file_tx(&file_guid, &file_name, STREAM_TOSERVER);
+ tx.vercmd.set_smb2_cmd(SMB2_COMMAND_WRITE);
+ tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER,
+ r.session_id, r.tree_id, 0); // TODO move into new_file_tx
if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
let file_id : u32 = tx.id as u32;
if wr.wr_offset < tdf.file_tracker.tracked {
set_event_fileoverlap = true;
}
- filetracker_newchunk(&mut tdf.file_tracker, files, flags,
- &file_name, wr.data, wr.wr_offset,
- wr.wr_len, false, &file_id);
+
+ if max_queue_size != 0 && tdf.file_tracker.get_inflight_size() + wr.wr_len as u64 > max_queue_size.into() {
+ event = Some(SMBEvent::WriteQueueSizeExceeded);
+ skip = Some((wr.wr_len, wr.data.len() as u32));
+ } else if max_queue_cnt != 0 && tdf.file_tracker.get_inflight_cnt() >= max_queue_cnt as usize {
+ event = Some(SMBEvent::WriteQueueSizeExceeded);
+ skip = Some((wr.wr_len, wr.data.len() as u32));
+ } else {
+ filetracker_newchunk(&mut tdf.file_tracker, files, flags,
+ &file_name, wr.data, wr.wr_offset,
+ wr.wr_len, false, &file_id);
+ }
}
- tx.vercmd.set_smb2_cmd(SMB2_COMMAND_WRITE);
- tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER,
- r.session_id, r.tree_id, 0); // TODO move into new_file_tx
+ }
+ if let Some(event) = event {
+ state.set_event(event);
+ }
+ if let Some((len, data_len)) = skip {
+ state.set_skip(STREAM_TOSERVER, len, data_len as u32);
}
}
const char *proto_name = "smb";
uint32_t max_read_size = 0;
uint32_t max_write_size = 0;
+ uint32_t max_write_queue_size = 0;
+ uint32_t max_write_queue_cnt = 0;
+ uint32_t max_read_queue_size = 0;
+ uint32_t max_read_queue_cnt = 0;
/** SMB */
if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
AppLayerProtoDetectRegisterProtocol(ALPROTO_SMB, proto_name);
}
SCLogConfig("SMB max-write-size: %u", max_write_size);
- rs_smb_set_conf_val(max_read_size, max_write_size);
+ ConfNode *wqs = ConfGetNode("app-layer.protocols.smb.max-write-queue-size");
+ if (wqs != NULL) {
+ uint32_t value;
+ if (ParseSizeStringU32(wqs->val, &value) < 0) {
+ SCLogError(
+ SC_ERR_SMB_CONFIG, "invalid value for max-write-queue-size %s", wqs->val);
+ } else {
+ max_write_queue_size = value;
+ }
+ }
+ SCLogConfig("SMB max-write-queue-size: %u", max_write_queue_size);
+
+ ConfNode *wqc = ConfGetNode("app-layer.protocols.smb.max-write-queue-cnt");
+ if (wqc != NULL) {
+ uint32_t value;
+ if (ParseSizeStringU32(wqc->val, &value) < 0) {
+ SCLogError(SC_ERR_SMB_CONFIG, "invalid value for max-write-queue-cnt %s", wqc->val);
+ } else {
+ max_write_queue_cnt = value;
+ }
+ }
+ SCLogConfig("SMB max-write-queue-cnt: %u", max_write_queue_cnt);
+
+ ConfNode *rqs = ConfGetNode("app-layer.protocols.smb.max-read-queue-size");
+ if (rqs != NULL) {
+ uint32_t value;
+ if (ParseSizeStringU32(rqs->val, &value) < 0) {
+ SCLogError(SC_ERR_SMB_CONFIG, "invalid value for max-read-queue-size %s", rqs->val);
+ } else {
+ max_read_queue_size = value;
+ }
+ }
+ SCLogConfig("SMB max-read-queue-size: %u", max_read_queue_size);
+
+ ConfNode *rqc = ConfGetNode("app-layer.protocols.smb.max-read-queue-cnt");
+ if (rqc != NULL) {
+ uint32_t value;
+ if (ParseSizeStringU32(rqc->val, &value) < 0) {
+ SCLogError(SC_ERR_SMB_CONFIG, "invalid value for max-read-queue-cnt %s", rqc->val);
+ } else {
+ max_read_queue_cnt = value;
+ }
+ }
+ SCLogConfig("SMB max-read-queue-cnt: %u", max_read_queue_cnt);
+
+ rs_smb_set_conf_val(max_read_size, max_write_size, max_write_queue_size,
+ max_write_queue_cnt, max_read_queue_size, max_read_queue_cnt);
} else {
SCLogConfig("Parsed disabled for %s protocol. Protocol detection"
"still on.", proto_name);