Reimplement the ssnguid2vec_map HashMap as a LruCache.
Since this is a DCERPC record cache, name it as such.
Default size is 128. Can be controlled by
`app-layer.protocols.smb.max-dcerpc-frag-cache-size`.
Ticket: #5672.
// msg_id 0 as this data crosses cmd/reply pairs
let ehdr = SMBHashKeyHdrGuid::new(SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG,
hdr.ssn_id, hdr.tree_id, 0_u64), guid.to_vec());
- let mut prevdata = state.ssnguid2vec_map.remove(&ehdr).unwrap_or_default();
+ let mut prevdata = state.dcerpc_rec_frag_cache.pop(&ehdr).unwrap_or_default();
SCLogDebug!("indata {} prevdata {}", indata.len(), prevdata.len());
prevdata.extend_from_slice(indata);
let data = prevdata;
if ntstatus == SMB_NTSTATUS_BUFFER_OVERFLOW && data.len() < dcer.frag_len as usize {
SCLogDebug!("short record {} < {}: storing partial data in state",
data.len(), dcer.frag_len);
- state.ssnguid2vec_map.insert(ehdr, data.to_vec());
+ state.dcerpc_rec_frag_cache.put(ehdr, data.to_vec());
return true; // TODO review
}
#[cfg(feature = "debug")]
pub fn _debug_state_stats(&self) {
- SCLogDebug!("ssn2vec_map {} guid2name_cache {} read_offset_cache {} ssn2tree_cache {} ssnguid2vec_map {} file_ts_guid {} file_tc_guid {} transactions {}",
+ SCLogDebug!("ssn2vec_map {} guid2name_cache {} read_offset_cache {} ssn2tree_cache {} dcerpc_rec_frag_cache {} file_ts_guid {} file_tc_guid {} transactions {}",
self.ssn2vec_map.len(),
self.guid2name_cache.len(),
self.read_offset_cache.len(),
self.ssn2tree_cache.len(),
- self.ssnguid2vec_map.len(),
+ self.dcerpc_rec_frag_cache.len(),
self.file_ts_guid.len(),
self.file_tc_guid.len(),
self.transactions.len());
pub static mut SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE: usize = 128;
/// For SMBState::ssn2tree_cache
pub static mut SMB_CFG_MAX_TREE_CACHE_SIZE: usize = 512;
+/// For SMBState::dcerpc_rec_frag_cache
+pub static mut SMB_CFG_MAX_FRAG_CACHE_SIZE: usize = 128;
static mut ALPROTO_SMB: AppProto = ALPROTO_UNKNOWN;
/// Map session key to SMBTree
pub ssn2tree_cache: LruCache<SMBCommonHdr, SMBTree>,
- // store partial data records that are transferred in multiple
- // requests for DCERPC.
- pub ssnguid2vec_map: HashMap<SMBHashKeyHdrGuid, Vec<u8>>,
+ /// store partial data records that are transferred in multiple
+ /// requests for DCERPC.
+ pub dcerpc_rec_frag_cache: LruCache<SMBHashKeyHdrGuid, Vec<u8>>,
skip_ts: u32,
skip_tc: u32,
guid2name_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_GUID_CACHE_SIZE }).unwrap()),
read_offset_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE }).unwrap()),
ssn2tree_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_TREE_CACHE_SIZE }).unwrap()),
- ssnguid2vec_map:HashMap::new(),
+ dcerpc_rec_frag_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_FRAG_CACHE_SIZE }).unwrap()),
skip_ts:0,
skip_tc:0,
file_ts_left:0,
SCLogError!("Invalid max-tree-cache-size value");
}
}
+ let retval = conf_get("app-layer.protocols.smb.max-dcerpc-frag-cache-size");
+ if let Some(val) = retval {
+ if let Ok(v) = val.parse::<usize>() {
+ if v > 0 {
+ SMB_CFG_MAX_FRAG_CACHE_SIZE = v;
+ } else {
+ SCLogError!("Invalid max-dcerpc-frag-cache-size value");
+ }
+ } else {
+ SCLogError!("Invalid max-dcerpc-frag-cache-size value");
+ }
+ }
SCLogConfig!("read: max record size: {}, max queued chunks {}, max queued size {}",
SMB_CFG_MAX_READ_SIZE, SMB_CFG_MAX_READ_QUEUE_CNT, SMB_CFG_MAX_READ_QUEUE_SIZE);
SCLogConfig!("write: max record size: {}, max queued chunks {}, max queued size {}",
if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW {
let key = SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid);
SCLogDebug!("SMBv1/TRANS: queueing data for len {} key {:?}", rd.data.len(), key);
- state.ssnguid2vec_map.insert(key, rd.data.to_vec());
+ state.dcerpc_rec_frag_cache.put(key, rd.data.to_vec());
} else if is_dcerpc {
SCLogDebug!("SMBv1 TRANS TO PIPE");
let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);