diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 396325912ad9..d23b4e76fcf4 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -186,6 +186,15 @@ jobs: cat eve.json | jq -c 'select(.dns)' test $(cat eve.json | jq -c 'select(.dns)' | wc -l) = "1" + - name: Test app-layer plugin + working-directory: examples/plugins/zabbix + run: | + RUSTFLAGS=-Clink-args=-Wl,-undefined,dynamic_lookup cargo build + ../../../src/suricata -S zabbix.rules --set plugins.0=./target/debug/libsuricata_zabbix.so --runmode=single -l . -c zabbix.yaml -k none -r ndpi_zabbix.pcap + cat eve.json | jq -c 'select(.zabbix)' + test $(cat eve.json | jq -c 'select(.zabbix)' | wc -l) = "6" + # we get 4 alerts and 2 zabbix events + - name: Test library build in tree working-directory: examples/lib/simple run: make clean all diff --git a/examples/plugins/README.md b/examples/plugins/README.md index 5300f750342b..1d0c9abee6f2 100644 --- a/examples/plugins/README.md +++ b/examples/plugins/README.md @@ -9,3 +9,7 @@ is useful if you want to send EVE output to custom destinations. A minimal capture plugin that can be used as a template, but also used for testing capture plugin loading and registration in CI. + +## zabbix + +An app-layer plugin for Zabbix protocol. diff --git a/examples/plugins/zabbix/Cargo.toml b/examples/plugins/zabbix/Cargo.toml new file mode 100644 index 000000000000..82711ca89cab --- /dev/null +++ b/examples/plugins/zabbix/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "suricata-zabbix" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +nom7 = { version="7.0", package="nom" } +libc = "~0.2.82" +flate2 = "1.0.34" + +[features] +default = ["suricata8"] +suricata7 = [] +suricata8 = [] diff --git a/examples/plugins/zabbix/LICENSE b/examples/plugins/zabbix/LICENSE new file mode 100644 index 000000000000..144c2324afc2 --- /dev/null +++ b/examples/plugins/zabbix/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Catena cyber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/plugins/zabbix/ndpi_zabbix.pcap b/examples/plugins/zabbix/ndpi_zabbix.pcap new file mode 100644 index 000000000000..8e3d32f5e891 Binary files /dev/null and b/examples/plugins/zabbix/ndpi_zabbix.pcap differ diff --git a/examples/plugins/zabbix/src/detect.rs b/examples/plugins/zabbix/src/detect.rs new file mode 100644 index 000000000000..bebf97d816da --- /dev/null +++ b/examples/plugins/zabbix/src/detect.rs @@ -0,0 +1,160 @@ +use crate::suricata::{ + rs_detect_u8_match, rs_detect_u8_parse, DetectBufferSetActiveList, + DetectHelperBufferMpmRegister, DetectHelperBufferRegister, DetectHelperGetData, + DetectHelperKeywordRegister, DetectHelperKeywordSetup, DetectSignatureSetAppProto, + DetectUintData, Level, SCSigTableElmt, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT, +}; +use crate::util::ctor_pointer; +use crate::util::SCLog; +use crate::zabbix::{ZabbixTransaction, ALPROTO_ZABBIX}; +use std::os::raw::{c_int, c_void}; + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_keywords_register() { + SCLog!(Level::Info, "registering Zabbix keywords"); + zabbix_register_flags_keyword(); + zabbix_register_data_keyword(); +} + +static mut G_ZABBIX_FLAGS_KWID: c_int = 0; +static mut G_ZABBIX_FLAGS_BUFFER_ID: c_int = 0; + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_flags_setup( + de: *mut c_void, + s: *mut c_void, + raw: *const std::os::raw::c_char, +) -> c_int { + let ctx = rs_detect_u8_parse(raw) as *mut std::os::raw::c_void; + if ctx.is_null() { + return -1; + } + let r = DetectHelperKeywordSetup( + de, + ALPROTO_ZABBIX, + G_ZABBIX_FLAGS_KWID, + G_ZABBIX_FLAGS_BUFFER_ID, + s, + ctx, + ); + if r < 0 { + rs_zabbix_flags_free(std::ptr::null_mut(), ctx); + } + r +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_flags_match( + _de: *mut c_void, + _f: *mut c_void, + _flags: u8, + _state: *mut c_void, + tx: *mut c_void, + _sig: *const c_void, + ctx: *const c_void, +) -> c_int { + let tx = ctor_pointer!(tx, ZabbixTransaction); + rs_detect_u8_match(tx.zabbix.flags, ctx) +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_flags_free(_de: *mut c_void, ctx: *mut c_void) { + // Just unbox... + let ctx = ctor_pointer!(ctx, DetectUintData); + std::mem::drop(Box::from_raw(ctx)); +} + +fn zabbix_register_flags_keyword() { + let kw = SCSigTableElmt { + name: b"zabbix.flags\0".as_ptr() as *const libc::c_char, + desc: b"match on zabbix header flags\0".as_ptr() as *const libc::c_char, + url: b"\0".as_ptr() as *const libc::c_char, + flags: 0, + AppLayerTxMatch: Some(rs_zabbix_flags_match), + Setup: rs_zabbix_flags_setup, + Free: Some(rs_zabbix_flags_free), + }; + unsafe { + G_ZABBIX_FLAGS_KWID = DetectHelperKeywordRegister(&kw); + G_ZABBIX_FLAGS_BUFFER_ID = DetectHelperBufferRegister( + b"zabbix_flags\0".as_ptr() as *const libc::c_char, + ALPROTO_ZABBIX, + true, + true, + ); + } +} + +static mut G_ZABBIX_DATA_BUFID: c_int = 0; + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_data_setup( + de: *mut c_void, + s: *mut c_void, + _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectBufferSetActiveList(de, s, G_ZABBIX_DATA_BUFID) < 0 { + return -1; + } + if DetectSignatureSetAppProto(s, ALPROTO_ZABBIX) != 0 { + return -1; + } + + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_data( + tx: *const c_void, + _flow_flags: u8, + buffer: *mut *const u8, + buffer_len: *mut u32, +) -> bool { + let tx = ctor_pointer!(tx, ZabbixTransaction); + *buffer = tx.zabbix.data.as_ptr(); + *buffer_len = tx.zabbix.data.len() as u32; + true +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_get_data( + de: *mut c_void, + transforms: *const c_void, + flow: *const c_void, + flow_flags: u8, + tx: *const c_void, + list_id: c_int, +) -> *mut c_void { + DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + rs_zabbix_data, + ) +} + +pub(super) fn zabbix_register_data_keyword() { + let kw = SCSigTableElmt { + name: b"zabbix.data\0".as_ptr() as *const libc::c_char, + desc: b"match on zabbix data\0".as_ptr() as *const libc::c_char, + url: b"\0".as_ptr() as *const libc::c_char, + Setup: rs_zabbix_data_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + unsafe { + DetectHelperKeywordRegister(&kw); + G_ZABBIX_DATA_BUFID = DetectHelperBufferMpmRegister( + b"zabbix_data\0".as_ptr() as *const libc::c_char, + b"zabbix data\0".as_ptr() as *const libc::c_char, + ALPROTO_ZABBIX, + true, + true, + rs_zabbix_get_data, + ); + } +} diff --git a/examples/plugins/zabbix/src/lib.rs b/examples/plugins/zabbix/src/lib.rs new file mode 100644 index 000000000000..2969e0c90341 --- /dev/null +++ b/examples/plugins/zabbix/src/lib.rs @@ -0,0 +1,7 @@ +mod detect; +mod log; +mod parser; +pub mod plugin; +mod suricata; +mod util; +mod zabbix; diff --git a/examples/plugins/zabbix/src/log.rs b/examples/plugins/zabbix/src/log.rs new file mode 100644 index 000000000000..4359177219f0 --- /dev/null +++ b/examples/plugins/zabbix/src/log.rs @@ -0,0 +1,76 @@ +use crate::suricata::JsonBuilder; +use crate::suricata::{jb_close, jb_open_object, jb_set_string, jb_set_uint}; +use crate::util::ctor_pointer; +use crate::zabbix::ZabbixTransaction; + +use std::ffi::CString; + +#[derive(Debug, PartialEq, Eq)] +pub enum JsonError { + SuricataError, +} + +impl std::error::Error for JsonError {} + +impl std::fmt::Display for JsonError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + JsonError::SuricataError => write!(f, "suricata returned error"), + } + } +} + +fn jb_set_string_sc(jb: &mut JsonBuilder, key: &str, val: &str) -> Result<(), JsonError> { + let keyc = CString::new(key).unwrap(); + let valc = CString::new(val.escape_default().to_string()).unwrap(); + if unsafe { !jb_set_string(jb, keyc.as_ptr(), valc.as_ptr()) } { + return Err(JsonError::SuricataError); + } + Ok(()) +} + +fn jb_close_sc(jb: &mut JsonBuilder) -> Result<(), JsonError> { + if unsafe { !jb_close(jb) } { + return Err(JsonError::SuricataError); + } + Ok(()) +} + +fn jb_open_object_sc(jb: &mut JsonBuilder, key: &str) -> Result<(), JsonError> { + let keyc = CString::new(key).unwrap(); + if unsafe { !jb_open_object(jb, keyc.as_ptr()) } { + return Err(JsonError::SuricataError); + } + Ok(()) +} + +fn jb_set_uint_sc(jb: &mut JsonBuilder, key: &str, val: u64) -> Result<(), JsonError> { + let keyc = CString::new(key).unwrap(); + if unsafe { !jb_set_uint(jb, keyc.as_ptr(), val) } { + return Err(JsonError::SuricataError); + } + Ok(()) +} + +fn log_zabbix(tx: &ZabbixTransaction, jb: &mut JsonBuilder) -> Result<(), JsonError> { + jb_open_object_sc(jb, "zabbix")?; + jb_set_uint_sc(jb, "flags", tx.zabbix.flags.into())?; + //TODO make configurable + if tx.zabbix.data.len() < 256 { + jb_set_string_sc(jb, "data", &String::from_utf8_lossy(&tx.zabbix.data))?; + } else { + jb_set_string_sc(jb, "data", &String::from_utf8_lossy(&tx.zabbix.data[..256]))?; + } + jb_close_sc(jb)?; + Ok(()) +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_log( + tx: *mut std::os::raw::c_void, + jb: *mut std::os::raw::c_void, +) -> bool { + let tx = ctor_pointer!(tx, ZabbixTransaction); + let jb = ctor_pointer!(jb, JsonBuilder); + log_zabbix(tx, jb).is_ok() +} diff --git a/examples/plugins/zabbix/src/parser.rs b/examples/plugins/zabbix/src/parser.rs new file mode 100644 index 000000000000..ec666f1ab42d --- /dev/null +++ b/examples/plugins/zabbix/src/parser.rs @@ -0,0 +1,68 @@ +use flate2::bufread::ZlibDecoder; +use nom7::bytes::streaming::take as takes; +use nom7::combinator::verify; +use nom7::number::streaming::{le_u32, le_u64, le_u8}; +use nom7::IResult; +use std::io::Read; + +#[derive(Clone, Debug, Default)] +pub struct ZabbixPdu { + pub flags: u8, + pub data: Vec, + pub wrong_decompressed_len: bool, + pub error_decompression: bool, + pub rem_len: u64, +} + +pub fn check_zabbix(i: &[u8]) -> bool { + let r = verify(le_u32::<&[u8], nom7::error::Error<&[u8]>>, |&v| { + v == 0x4458425a + })(i); + r.is_ok() +} + +pub fn parse_zabbix(i: &[u8]) -> IResult<&[u8], ZabbixPdu> { + let (i, _magic) = le_u32(i)?; + let (i, flags) = le_u8(i)?; + let large = (flags & 4) != 0; + let (i, (pdu_len, decompressed_len)) = if large { + let (i2, pdu_len) = le_u64(i)?; + let (i2, decompressed_len) = le_u64(i2)?; + Ok((i2, (pdu_len, decompressed_len))) + } else { + let (i2, pdu_len) = le_u32(i)?; + let (i2, decompressed_len) = le_u32(i2)?; + Ok((i2, (pdu_len as u64, decompressed_len as u64))) + }?; + let mut wrong_decompressed_len = false; + let mut error_decompression = false; + //TODO make configurable + let take_len = std::cmp::min(pdu_len, 4096); + let (i, data) = takes(pdu_len as usize)(i)?; + let rem_len = take_len - pdu_len; + let data = if (flags & 2) != 0 { + let mut z = ZlibDecoder::new(data); + let mut dec_data = Vec::new(); + if let Ok(n) = z.read_to_end(&mut dec_data) { + if n as u64 != decompressed_len { + wrong_decompressed_len = true; + } + dec_data + } else { + error_decompression = true; + data.to_vec() + } + } else { + data.to_vec() + }; + Ok(( + i, + ZabbixPdu { + flags, + data, + wrong_decompressed_len, + error_decompression, + rem_len, + }, + )) +} diff --git a/examples/plugins/zabbix/src/plugin.rs b/examples/plugins/zabbix/src/plugin.rs new file mode 100644 index 000000000000..2b0e5f9c6d9a --- /dev/null +++ b/examples/plugins/zabbix/src/plugin.rs @@ -0,0 +1,35 @@ +use super::suricata; +use super::zabbix::rs_zabbix_register_parser; +use crate::detect::rs_zabbix_keywords_register; +use crate::log::rs_zabbix_log; +use crate::suricata::{SCAppLayerPlugin, SCPlugin, SCPluginRegisterAppLayer}; +use crate::util::SCLog; + +extern "C" fn zabbix_plugin_init() { + SCLog!(suricata::Level::Notice, "Initializing zabbix plugin"); + let plugin = SCAppLayerPlugin { + version: 8, + name: b"zabbix\0".as_ptr() as *const libc::c_char, + logname: b"JsonZabbixLog\0".as_ptr() as *const libc::c_char, + confname: b"eve-log.zabbix\0".as_ptr() as *const libc::c_char, + Register: rs_zabbix_register_parser, + Logger: rs_zabbix_log, + KeywordsRegister: rs_zabbix_keywords_register, + }; + unsafe { + if SCPluginRegisterAppLayer(Box::into_raw(Box::new(plugin))) != 0 { + println!("Failed to register zabbix plugin"); + } + } +} + +#[no_mangle] +extern "C" fn SCPluginRegister() -> *const SCPlugin { + let plugin = SCPlugin { + name: b"zabbix\0".as_ptr() as *const libc::c_char, + license: b"MIT\0".as_ptr() as *const libc::c_char, + author: b"Philippe Antoine\0".as_ptr() as *const libc::c_char, + Init: zabbix_plugin_init, + }; + Box::into_raw(Box::new(plugin)) +} diff --git a/examples/plugins/zabbix/src/suricata.rs b/examples/plugins/zabbix/src/suricata.rs new file mode 100644 index 000000000000..0bebc36fb576 --- /dev/null +++ b/examples/plugins/zabbix/src/suricata.rs @@ -0,0 +1,551 @@ +// This file is kind of the include required by API +// completed by helper functions + +use std::os::raw::{c_char, c_int, c_void}; + +pub type AppProto = u16; +pub const ALPROTO_UNKNOWN: AppProto = 0; + +#[repr(C)] +#[allow(non_snake_case)] +pub struct SCPlugin { + pub name: *const libc::c_char, + pub license: *const libc::c_char, + pub author: *const libc::c_char, + pub Init: extern "C" fn(), +} + +#[repr(C)] +#[derive(Default, Debug, PartialEq, Eq)] +pub struct AppLayerTxConfig { + log_flags: u8, +} + +#[repr(C)] +#[derive(Default, Debug, PartialEq, Eq)] +pub struct LoggerFlags { + flags: u32, +} + +pub enum DetectEngineState {} +pub enum AppLayerDecoderEvents {} + +#[repr(C)] +#[derive(Debug, PartialEq, Eq)] +pub struct AppLayerTxData { + pub config: AppLayerTxConfig, + logged: LoggerFlags, + pub files_opened: u32, + pub files_logged: u32, + pub files_stored: u32, + + pub file_flags: u16, + pub file_tx: u8, + + detect_flags_ts: u64, + detect_flags_tc: u64, + + de_state: *mut DetectEngineState, + pub events: *mut AppLayerDecoderEvents, +} + +#[repr(C)] +#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)] +pub struct AppLayerStateData { + pub file_flags: u16, +} + +#[repr(C)] +#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)] +pub struct AppLayerResult { + pub status: i32, + pub consumed: u32, + pub needed: u32, +} + +pub enum Flow {} + +#[repr(C)] +pub struct StreamSlice { + input: *const u8, + input_len: u32, + flags: u8, + offset: u64, +} + +#[repr(C)] +pub struct AppLayerGetTxIterTuple { + tx_ptr: *mut std::os::raw::c_void, + tx_id: u64, + has_next: bool, +} + +pub const IPPROTO_TCP: u8 = 6; + +pub type AppLayerEventType = c_int; + +pub const APP_LAYER_TX_SKIP_INSPECT_FLAG: u64 = 0x4000000000000000; +pub const APP_LAYER_PARSER_OPT_ACCEPT_GAPS: u32 = 0x00000001; + +pub const STREAM_TOSERVER: u8 = 0x04; +//pub const STREAM_TOCLIENT: u8 = 0x08; + +// only in Suricata 7 +#[repr(C)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum Direction { + ToServer = 0x04, + ToClient = 0x08, +} + +#[repr(C)] +#[derive(Debug)] +pub struct FileContainer { + pub head: *mut c_void, + pub tail: *mut c_void, +} + +// exists also in 6 but only constructed in 7 for this plugin +#[repr(C)] +pub struct StreamingBufferConfig { + pub buf_size: u32, + + pub max_regions: u16, + pub region_gap: u32, + // do not bother with real prototypes + pub calloc: Option, + pub realloc: Option, + pub free: Option, +} + +#[allow(non_snake_case)] +#[repr(C)] +pub struct AppLayerGetFileState { + pub fc: *mut FileContainer, + pub cfg: *const StreamingBufferConfig, +} + +pub type ParseFn = unsafe extern "C" fn( + flow: *const Flow, + state: *mut c_void, + pstate: *mut c_void, + stream_slice: StreamSlice, + data: *const c_void, +) -> AppLayerResult; +pub type ProbeFn = unsafe extern "C" fn( + flow: *const Flow, + flags: u8, + input: *const u8, + input_len: u32, + rdir: *mut u8, +) -> AppProto; +pub type StateAllocFn = extern "C" fn(*mut c_void, AppProto) -> *mut c_void; +pub type StateFreeFn = unsafe extern "C" fn(*mut c_void); +pub type StateTxFreeFn = unsafe extern "C" fn(*mut c_void, u64); +pub type StateGetTxFn = unsafe extern "C" fn(*mut c_void, u64) -> *mut c_void; +pub type StateGetTxCntFn = unsafe extern "C" fn(*mut c_void) -> u64; + +pub type StateGetProgressFn = unsafe extern "C" fn(*mut c_void, u8) -> c_int; +pub type GetEventInfoFn = + unsafe extern "C" fn(*const c_char, *mut c_int, *mut AppLayerEventType) -> c_int; +pub type GetEventInfoByIdFn = + unsafe extern "C" fn(c_int, *mut *const c_char, *mut AppLayerEventType) -> i8; +pub type LocalStorageNewFn = extern "C" fn() -> *mut c_void; +pub type LocalStorageFreeFn = extern "C" fn(*mut c_void); + +pub type GetTxFilesFn = unsafe extern "C" fn(*mut c_void, *mut c_void, u8) -> AppLayerGetFileState; + +pub type GetTxIteratorFn = unsafe extern "C" fn( + ipproto: u8, + alproto: AppProto, + state: *mut c_void, + min_tx_id: u64, + max_tx_id: u64, + istate: &mut u64, +) -> AppLayerGetTxIterTuple; +pub type GetTxDataFn = unsafe extern "C" fn(*mut c_void) -> *mut AppLayerTxData; + +pub type GetStateDataFn = unsafe extern "C" fn(*mut c_void) -> *mut AppLayerStateData; + +pub type ApplyTxConfigFn = unsafe extern "C" fn(*mut c_void, *mut c_void, c_int, AppLayerTxConfig); + +pub type GetFrameIdByName = unsafe extern "C" fn(*const c_char) -> c_int; +pub type GetFrameNameById = unsafe extern "C" fn(u8) -> *const c_char; + +#[repr(C)] +pub struct RustParser { + pub name: *const c_char, + pub default_port: *const c_char, + pub ipproto: u8, + pub probe_ts: Option, + pub probe_tc: Option, + pub min_depth: u16, + pub max_depth: u16, + pub state_new: StateAllocFn, + pub state_free: StateFreeFn, + pub parse_ts: ParseFn, + pub parse_tc: ParseFn, + pub get_tx_count: StateGetTxCntFn, + pub get_tx: StateGetTxFn, + pub tx_free: StateTxFreeFn, + + pub tx_comp_st_ts: c_int, + pub tx_comp_st_tc: c_int, + pub tx_get_progress: StateGetProgressFn, + + pub get_eventinfo: Option, + pub get_eventinfo_byid: Option, + pub localstorage_new: Option, + pub localstorage_free: Option, + + pub get_tx_files: Option, + + pub get_tx_iterator: Option, + + pub get_state_data: GetStateDataFn, + + pub get_tx_data: GetTxDataFn, + pub apply_tx_config: Option, + pub flags: u32, + pub get_frame_id_by_name: Option, + pub get_frame_name_by_id: Option, +} + +pub const APP_LAYER_EVENT_TYPE_TRANSACTION: i32 = 1; + +pub const SIGMATCH_NOOPT: u16 = 1; +pub const SIGMATCH_INFO_STICKY_BUFFER: u16 = 0x200; + +#[allow(dead_code)] +#[derive(Debug)] +#[repr(C)] +pub enum Level { + NotSet = -1, + None = 0, + + Error, + Warning, + Notice, + Info, + Perf, + Config, + Debug, +} + +#[repr(C)] +#[allow(non_snake_case)] +pub struct SCAppLayerPlugin { + pub version: u64, + pub name: *const libc::c_char, + pub Register: unsafe extern "C" fn(), + pub KeywordsRegister: unsafe extern "C" fn(), + pub logname: *const libc::c_char, + pub confname: *const libc::c_char, + pub Logger: + unsafe extern "C" fn(tx: *mut std::os::raw::c_void, jb: *mut std::os::raw::c_void) -> bool, +} + +#[repr(C)] +#[allow(non_snake_case)] +pub struct SCSigTableElmt { + pub name: *const libc::c_char, + pub desc: *const libc::c_char, + pub url: *const libc::c_char, + pub flags: u16, + pub Setup: unsafe extern "C" fn( + de: *mut c_void, + s: *mut c_void, + raw: *const std::os::raw::c_char, + ) -> c_int, + pub Free: Option, + pub AppLayerTxMatch: Option< + unsafe extern "C" fn( + de: *mut c_void, + f: *mut c_void, + flags: u8, + state: *mut c_void, + tx: *mut c_void, + sig: *const c_void, + ctx: *const c_void, + ) -> c_int, + >, +} + +#[derive(PartialEq, Eq, Clone, Debug)] +#[repr(u8)] +pub enum DetectUintMode { + _DetectUintModeEqual, +} + +#[derive(Debug)] +#[repr(C)] +pub struct DetectUintData { + pub arg1: T, + pub arg2: T, + pub mode: DetectUintMode, +} + +extern "C" { + pub fn StringToAppProto(proto_name: *const u8) -> AppProto; + pub fn SCLogMessage( + level: c_int, + filename: *const std::os::raw::c_char, + line: std::os::raw::c_uint, + function: *const std::os::raw::c_char, + subsystem: *const std::os::raw::c_char, + message: *const std::os::raw::c_char, + ) -> c_int; + + pub fn AppLayerProtoDetectConfProtoDetectionEnabled( + ipproto: *const c_char, + proto: *const c_char, + ) -> c_int; + + pub fn AppLayerRegisterProtocolDetection( + parser: *const RustParser, + enable_default: c_int, + ) -> AppProto; + pub fn AppLayerProtoDetectPMRegisterPatternCS( + ipproto: u8, + alproto: AppProto, + pattern: *const c_char, + depth: u16, + offset: u16, + direction: u8, + ) -> c_int; + pub fn AppLayerParserConfParserEnabled(ipproto: *const c_char, proto: *const c_char) -> c_int; + pub fn AppLayerRegisterParser(parser: *const RustParser, alproto: AppProto) -> c_int; + pub fn SCPluginRegisterAppLayer(plugin: *const SCAppLayerPlugin) -> c_int; + pub fn AppLayerDecoderEventsSetEventRaw(events: *mut *mut AppLayerDecoderEvents, event: u8); + pub fn AppLayerParserRegisterLogger(pproto: u8, alproto: AppProto); + pub fn DetectHelperBufferRegister( + name: *const c_char, + alproto: AppProto, + toclient: bool, + toserver: bool, + ) -> c_int; + pub fn DetectHelperBufferMpmRegister( + name: *const c_char, + desc: *const c_char, + alproto: AppProto, + toclient: bool, + toserver: bool, + get_data: unsafe extern "C" fn( + *mut c_void, + *const c_void, + *const c_void, + u8, + *const c_void, + i32, + ) -> *mut c_void, + ) -> c_int; + pub fn DetectHelperGetData( + de: *mut c_void, + transforms: *const c_void, + flow: *const c_void, + flow_flags: u8, + tx: *const c_void, + list_id: c_int, + get_buf: unsafe extern "C" fn(*const c_void, u8, *mut *const u8, *mut u32) -> bool, + ) -> *mut c_void; + pub fn DetectHelperKeywordRegister(kw: *const SCSigTableElmt) -> c_int; + pub fn DetectSignatureSetAppProto(s: *mut c_void, alproto: AppProto) -> c_int; + pub fn DetectBufferSetActiveList(de: *mut c_void, s: *mut c_void, bufid: c_int) -> c_int; + + pub fn SigMatchAppendSMToList( + de_ctx: *mut c_void, + s: *mut c_void, + kw_id: c_int, + ctx: *mut c_void, + buf_id: c_int, + ) -> *mut c_void; + pub fn rs_detect_u8_match(parg: u8, ctx: *const c_void) -> c_int; + pub fn rs_detect_u8_parse(raw: *const c_char) -> *mut DetectUintData; +} + +// jsonbuilder +pub enum JsonBuilder {} + +extern "C" { + pub fn jb_set_string(jb: &mut JsonBuilder, key: *const c_char, val: *const c_char) -> bool; + pub fn jb_close(jb: &mut JsonBuilder) -> bool; + pub fn jb_open_object(jb: &mut JsonBuilder, key: *const c_char) -> bool; + pub fn jb_set_uint(jb: &mut JsonBuilder, key: *const c_char, val: u64) -> bool; +} + +// Helper functions + +#[allow(non_snake_case)] +pub unsafe fn DetectHelperKeywordSetup( + de_ctx: *mut c_void, + alproto: AppProto, + kw_id: c_int, + buf_id: c_int, + s: *mut c_void, + ctx: *mut c_void, +) -> c_int { + if DetectSignatureSetAppProto(s, alproto) != 0 { + return -1; + } + if SigMatchAppendSMToList(de_ctx, s, kw_id, ctx, buf_id).is_null() { + return -1; + } + 0 +} + +impl AppLayerResult { + pub fn ok() -> Self { + Default::default() + } + pub fn err() -> Self { + Self { + status: -1, + ..Default::default() + } + } + pub fn incomplete(consumed: u32, needed: u32) -> Self { + Self { + status: 1, + consumed, + needed, + } + } +} + +impl Direction { + pub fn index(&self) -> usize { + match self { + Direction::ToServer => 0, + Direction::ToClient => 1, + } + } +} + +impl StreamSlice { + pub fn as_slice(&self) -> &[u8] { + if self.input.is_null() && self.input_len == 0 { + unsafe { + return std::slice::from_raw_parts( + std::ptr::NonNull::::dangling().as_ptr(), + self.input_len as usize, + ); + } + } + unsafe { std::slice::from_raw_parts(self.input, self.input_len as usize) } + } + pub fn flags(&self) -> u8 { + self.flags + } + pub fn is_gap(&self) -> bool { + self.input.is_null() && self.input_len > 0 + } +} + +impl AppLayerGetTxIterTuple { + pub fn with_values( + tx_ptr: *mut std::os::raw::c_void, + tx_id: u64, + has_next: bool, + ) -> AppLayerGetTxIterTuple { + AppLayerGetTxIterTuple { + tx_ptr, + tx_id, + has_next, + } + } + pub fn not_found() -> AppLayerGetTxIterTuple { + AppLayerGetTxIterTuple { + tx_ptr: std::ptr::null_mut(), + tx_id: 0, + has_next: false, + } + } +} + +impl AppLayerTxData { + pub fn for_direction(direction: Direction) -> Self { + let (detect_flags_ts, detect_flags_tc) = match direction { + Direction::ToServer => (0, APP_LAYER_TX_SKIP_INSPECT_FLAG), + Direction::ToClient => (APP_LAYER_TX_SKIP_INSPECT_FLAG, 0), + }; + Self { + config: AppLayerTxConfig::default(), + logged: LoggerFlags::default(), + files_opened: 0, + files_logged: 0, + files_stored: 0, + file_flags: 0, + file_tx: 0, + detect_flags_ts, + detect_flags_tc, + de_state: std::ptr::null_mut(), + events: std::ptr::null_mut(), + } + } + pub fn set_event(&mut self, event: u8) { + unsafe { + AppLayerDecoderEventsSetEventRaw(&mut self.events, event); + } + } +} + +pub struct Frame { + pub _id: i64, +} + +impl Frame { + #[allow(clippy::not_unsafe_ptr_arg_deref)] + pub fn new( + flow: *const Flow, + stream_slice: &StreamSlice, + frame_start: &[u8], + frame_len: i64, + frame_type: u8, + tx_id: u64, + ) -> Option { + let offset = frame_start.as_ptr() as usize - stream_slice.as_slice().as_ptr() as usize; + let frame = unsafe { + AppLayerFrameNewByRelativeOffset( + flow, + stream_slice, + offset as u32, + frame_len, + (stream_slice.flags() & STREAM_TOSERVER == 0).into(), + frame_type, + ) + }; + let id = unsafe { AppLayerFrameGetId(frame) }; + if id > 0 { + let direction = if stream_slice.flags() & STREAM_TOSERVER != 0 { + 0 + } else { + 1 + }; + unsafe { + AppLayerFrameSetTxIdById(flow, direction, id, tx_id); + }; + Some(Self { _id: id }) + } else { + None + } + } +} + +#[repr(C)] +struct CFrame { + _private: [u8; 0], +} + +// Defined in app-layer-register.h +extern "C" { + fn AppLayerFrameNewByRelativeOffset( + flow: *const Flow, + stream_slice: *const StreamSlice, + frame_start_rel: u32, + len: i64, + dir: i32, + frame_type: u8, + ) -> *const CFrame; + pub fn AppLayerFrameSetTxIdById(flow: *const Flow, dir: i32, id: i64, tx_id: u64); + fn AppLayerFrameGetId(frame: *const CFrame) -> i64; +} diff --git a/examples/plugins/zabbix/src/util.rs b/examples/plugins/zabbix/src/util.rs new file mode 100644 index 000000000000..31096329c5ee --- /dev/null +++ b/examples/plugins/zabbix/src/util.rs @@ -0,0 +1,55 @@ +// Helper macros +use crate::suricata::{Level, SCLogMessage}; + +use std::ffi::CString; + +macro_rules! ctor_pointer { + ($ptr:ident, $ty:ty) => { + &mut *($ptr as *mut $ty) + }; +} +pub(crate) use ctor_pointer; + +// This macro returns the function name. +// +// This macro has been borrowed from https://github.com/popzxc/stdext-rs, which +// is released under the MIT license as there is currently no macro in Rust +// to provide the function name. +macro_rules! function { + () => {{ + // Okay, this is ugly, I get it. However, this is the best we can get on a stable rust. + fn __f() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + let name = type_name_of(__f); + &name[..name.len() - 5] + }}; +} +pub(crate) use function; + +macro_rules!SCLog { + ($level:expr, $($arg:tt)*) => { + $crate::util::sclog($level, file!(), line!(), crate::util::function!(), + &(format!($($arg)*))); + } +} + +pub(crate) use SCLog; + +pub fn sclog(level: Level, filename: &str, line: u32, function: &str, message: &str) { + let filenamec = CString::new(filename).unwrap(); + let functionc = CString::new(function).unwrap(); + let modulec = CString::new("zabbix").unwrap(); + let messagec = CString::new(message).unwrap(); + unsafe { + SCLogMessage( + level as i32, + filenamec.as_ptr(), + line, + (functionc).as_ptr(), + (modulec).as_ptr(), + (messagec).as_ptr(), + ); + } +} diff --git a/examples/plugins/zabbix/src/zabbix.rs b/examples/plugins/zabbix/src/zabbix.rs new file mode 100644 index 000000000000..c41943ecd73d --- /dev/null +++ b/examples/plugins/zabbix/src/zabbix.rs @@ -0,0 +1,507 @@ +use super::parser; +use super::suricata::{ + AppLayerGetTxIterTuple, AppLayerParserConfParserEnabled, AppLayerParserRegisterLogger, + AppLayerProtoDetectConfProtoDetectionEnabled, AppLayerProtoDetectPMRegisterPatternCS, + AppLayerRegisterParser, AppLayerRegisterProtocolDetection, AppLayerResult, AppLayerStateData, + AppLayerTxData, AppProto, Direction, Flow, Frame, Level, RustParser, StreamSlice, + StringToAppProto, ALPROTO_UNKNOWN, APP_LAYER_EVENT_TYPE_TRANSACTION, + APP_LAYER_PARSER_OPT_ACCEPT_GAPS, IPPROTO_TCP, +}; +use crate::util::{ctor_pointer, SCLog}; +use std::collections::VecDeque; +use std::ffi::CStr; +use std::ffi::CString; +use std::os::raw::{c_char, c_int, c_void}; + +pub(crate) static mut ALPROTO_ZABBIX: AppProto = ALPROTO_UNKNOWN; +static mut ALPROTO_FAILED: AppProto = 0xFFFF; + +#[derive(Debug, PartialEq, Eq)] +pub enum ZabbixEvent { + ErrorDecompression, + WrongDecompressedLen, +} + +impl ZabbixEvent { + fn from_id(id: i32) -> Option { + match id { + 0 => Some(ZabbixEvent::ErrorDecompression), + 1 => Some(ZabbixEvent::WrongDecompressedLen), + _ => None, + } + } + + fn to_cstring(&self) -> &str { + match *self { + ZabbixEvent::ErrorDecompression => "error_decompression\0", + ZabbixEvent::WrongDecompressedLen => "wrong_decompressed_len\0", + } + } + + fn as_i32(&self) -> i32 { + match *self { + ZabbixEvent::ErrorDecompression => 0, + ZabbixEvent::WrongDecompressedLen => 1, + } + } + + fn from_string(s: &str) -> Option { + match s { + "error_decompression" => Some(ZabbixEvent::ErrorDecompression), + "wrong_decompressed_len" => Some(ZabbixEvent::WrongDecompressedLen), + _ => None, + } + } + + pub unsafe extern "C" fn get_event_info( + event_name: *const std::os::raw::c_char, + event_id: *mut std::os::raw::c_int, + event_type: *mut std::os::raw::c_int, + ) -> std::os::raw::c_int { + if event_name.is_null() { + return -1; + } + + let event = match CStr::from_ptr(event_name) + .to_str() + .map(ZabbixEvent::from_string) + { + Ok(Some(event)) => event.as_i32(), + _ => { + return -1; + } + }; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + *event_id = event as std::os::raw::c_int; + 0 + } + + pub unsafe extern "C" fn get_event_info_by_id( + event_id: std::os::raw::c_int, + event_name: *mut *const std::os::raw::c_char, + event_type: *mut std::os::raw::c_int, + ) -> i8 { + if let Some(e) = ZabbixEvent::from_id(event_id) { + *event_name = e.to_cstring().as_ptr() as *const std::os::raw::c_char; + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + return 0; + } + -1 + } +} + +pub enum ZabbixFrameType { + Pdu, + Hdr, + Data, +} + +impl ZabbixFrameType { + fn from_u8(id: u8) -> Option { + match id { + 0 => Some(ZabbixFrameType::Pdu), + 1 => Some(ZabbixFrameType::Hdr), + 2 => Some(ZabbixFrameType::Data), + _ => None, + } + } + + fn to_cstring(&self) -> *const std::os::raw::c_char { + let s = match *self { + ZabbixFrameType::Pdu => "pdu\0", + ZabbixFrameType::Hdr => "hdr\0", + ZabbixFrameType::Data => "data\0", + }; + s.as_ptr() as *const std::os::raw::c_char + } + + fn as_u8(&self) -> u8 { + match *self { + ZabbixFrameType::Pdu => 0, + ZabbixFrameType::Hdr => 1, + ZabbixFrameType::Data => 2, + } + } + + fn from_str(s: &str) -> Option { + match s { + "pdu" => Some(ZabbixFrameType::Pdu), + "hdr" => Some(ZabbixFrameType::Hdr), + "data" => Some(ZabbixFrameType::Data), + _ => None, + } + } + + pub unsafe extern "C" fn ffi_id_from_name(name: *const std::os::raw::c_char) -> i32 { + if name.is_null() { + return -1; + } + let frame_id = if let Ok(s) = std::ffi::CStr::from_ptr(name).to_str() { + ZabbixFrameType::from_str(s) + .map(|t| t.as_u8() as i32) + .unwrap_or(-1) + } else { + -1 + }; + frame_id + } + + pub unsafe extern "C" fn ffi_name_from_id(id: u8) -> *const std::os::raw::c_char { + ZabbixFrameType::from_u8(id) + .map(|s| s.to_cstring()) + .unwrap_or_else(std::ptr::null) + } +} + +pub struct ZabbixTransaction { + tx_id: u64, + pub zabbix: parser::ZabbixPdu, + tx_data: AppLayerTxData, +} + +impl ZabbixTransaction { + pub fn new(dir: Direction) -> ZabbixTransaction { + Self { + tx_id: 0, + zabbix: parser::ZabbixPdu::default(), + tx_data: AppLayerTxData::for_direction(dir), + } + } + pub fn set_event(&mut self, event: u8) { + self.tx_data.set_event(event); + } +} + +#[derive(Default)] +pub struct ZabbixState { + state_data: AppLayerStateData, + tx_id: u64, + transactions: VecDeque, + in_gap: [bool; 2], + to_skip: [usize; 2], +} + +impl ZabbixState { + pub fn new() -> Self { + Default::default() + } + + // Free a transaction by ID. + fn free_tx(&mut self, tx_id: u64) { + let len = self.transactions.len(); + let mut found = false; + let mut index = 0; + for i in 0..len { + let tx = &self.transactions[i]; + if tx.tx_id == tx_id + 1 { + found = true; + index = i; + break; + } + } + if found { + self.transactions.remove(index); + } + } + + pub fn get_tx(&mut self, tx_id: u64) -> Option<&ZabbixTransaction> { + self.transactions.iter().find(|tx| tx.tx_id == tx_id + 1) + } + + fn process_frames( + zabbix: &parser::ZabbixPdu, + stream_slice: &StreamSlice, + flow: *const Flow, + input: &[u8], + remlen: usize, + tx_id: u64, + ) { + let hdrlen = if (zabbix.flags & 4) != 0 { + 4 + 1 + 2 * 8 + } else { + 4 + 1 + 2 * 4 + }; + let _pdu = Frame::new( + flow, + stream_slice, + input, + (input.len() - remlen) as i64, + ZabbixFrameType::Pdu as u8, + tx_id, + ); + let _hdr = Frame::new( + flow, + stream_slice, + input, + hdrlen as i64, + ZabbixFrameType::Hdr as u8, + tx_id, + ); + let _data = Frame::new( + flow, + stream_slice, + &input[hdrlen..], + (input.len() - remlen - hdrlen) as i64, + ZabbixFrameType::Data as u8, + tx_id, + ); + } + + fn parse_zabbix( + &mut self, + dir: Direction, + flow: *const Flow, + stream_slice: StreamSlice, + ) -> AppLayerResult { + if stream_slice.is_gap() { + self.in_gap[dir.index()] = true; + return AppLayerResult::ok(); + } + let input = stream_slice.as_slice(); + if self.in_gap[dir.index()] { + if parser::check_zabbix(input) { + self.in_gap[dir.index()] = false; + } else { + return AppLayerResult::ok(); + } + } + let mut start = input; + while !start.is_empty() { + if self.to_skip[dir.index()] > start.len() { + self.to_skip[dir.index()] -= start.len(); + return AppLayerResult::ok(); + } + start = &start[self.to_skip[dir.index()]..]; + match parser::parse_zabbix(start) { + Ok((rem, h)) => { + let mut tx = ZabbixTransaction::new(dir); + self.tx_id += 1; + tx.tx_id = self.tx_id; + ZabbixState::process_frames( + &h, + &stream_slice, + flow, + start, + rem.len(), + tx.tx_id, + ); + if h.error_decompression { + tx.set_event(ZabbixEvent::ErrorDecompression as u8); + } + if h.wrong_decompressed_len { + tx.set_event(ZabbixEvent::WrongDecompressedLen as u8); + } + self.to_skip[dir.index()] = h.rem_len as usize; + tx.zabbix = h; + self.transactions.push_back(tx); + start = rem; + } + Err(nom7::Err::Incomplete(n1)) => { + if let nom7::Needed::Size(n2) = n1 { + let consumed = input.len() - start.len(); + let needed = start.len() + usize::from(n2); + return AppLayerResult::incomplete(consumed as u32, needed as u32); + } else { + return AppLayerResult::err(); + } + } + Err(_) => { + return AppLayerResult::err(); + } + } + } + + // Input was fully consumed. + AppLayerResult::ok() + } +} + +// C exports. + +extern "C" fn rs_zabbix_state_new(_orig_state: *mut c_void, _orig_proto: AppProto) -> *mut c_void { + let state = ZabbixState::new(); + let boxed = Box::new(state); + Box::into_raw(boxed) as *mut c_void +} + +unsafe extern "C" fn rs_zabbix_state_free(state: *mut c_void) { + std::mem::drop(Box::from_raw(state as *mut ZabbixState)); +} + +unsafe extern "C" fn rs_zabbix_state_tx_free(state: *mut c_void, tx_id: u64) { + let state = ctor_pointer!(state, ZabbixState); + state.free_tx(tx_id); +} + +unsafe extern "C" fn rs_zabbix_parse_request( + _flow: *const Flow, + state: *mut c_void, + _pstate: *mut c_void, + stream_slice: StreamSlice, + _data: *const c_void, +) -> AppLayerResult { + let state = ctor_pointer!(state, ZabbixState); + state.parse_zabbix(Direction::ToServer, _flow, stream_slice) +} + +unsafe extern "C" fn rs_zabbix_parse_response( + _flow: *const Flow, + state: *mut c_void, + _pstate: *mut c_void, + stream_slice: StreamSlice, + _data: *const c_void, +) -> AppLayerResult { + let state = ctor_pointer!(state, ZabbixState); + state.parse_zabbix(Direction::ToClient, _flow, stream_slice) +} + +unsafe extern "C" fn rs_zabbix_state_get_tx(state: *mut c_void, tx_id: u64) -> *mut c_void { + let state = ctor_pointer!(state, ZabbixState); + match state.get_tx(tx_id) { + Some(tx) => tx as *const _ as *mut _, + None => std::ptr::null_mut(), + } +} + +unsafe extern "C" fn rs_zabbix_state_get_tx_count(state: *mut c_void) -> u64 { + let state = ctor_pointer!(state, ZabbixState); + state.tx_id +} + +unsafe extern "C" fn rs_zabbix_tx_get_alstate_progress(_tx: *mut c_void, _direction: u8) -> c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_get_tx_data( + tx: *mut std::os::raw::c_void, +) -> *mut AppLayerTxData { + let tx = &mut *(tx as *mut ZabbixTransaction); + &mut tx.tx_data +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_get_state_data( + state: *mut std::os::raw::c_void, +) -> *mut AppLayerStateData { + let state = &mut *(state as *mut ZabbixState); + &mut state.state_data +} + +pub unsafe extern "C" fn zabbix_get_tx_iterator( + _ipproto: u8, + _alproto: AppProto, + state: *mut std::os::raw::c_void, + min_tx_id: u64, + _max_tx_id: u64, + istate: &mut u64, +) -> AppLayerGetTxIterTuple { + let state = ctor_pointer!(state, ZabbixState); + let mut index = *istate as usize; + let len = state.transactions.len(); + while index < len { + let tx = state.transactions.get(index).unwrap(); + if tx.tx_id < min_tx_id + 1 { + index += 1; + continue; + } + *istate = index as u64; + return AppLayerGetTxIterTuple::with_values( + tx as *const _ as *mut _, + tx.tx_id - 1, + len - index > 1, + ); + } + AppLayerGetTxIterTuple::not_found() +} + +#[no_mangle] +pub extern "C" fn rs_zabbix_state_progress_completion_status( + _direction: u8, +) -> std::os::raw::c_int { + 1 +} + +#[no_mangle] +pub unsafe extern "C" fn rs_zabbix_register_parser() { + SCLog!(Level::Notice, "Registering zabbix parser"); + //let default_port = CString::new("[10050]").unwrap(); + let parser = RustParser { + name: b"zabbix\0".as_ptr() as *const c_char, + default_port: std::ptr::null(), + ipproto: IPPROTO_TCP, + probe_ts: None, + probe_tc: None, + min_depth: 16, + max_depth: 16, + state_new: rs_zabbix_state_new, + state_free: rs_zabbix_state_free, + tx_free: rs_zabbix_state_tx_free, + parse_ts: rs_zabbix_parse_request, + parse_tc: rs_zabbix_parse_response, + get_tx_count: rs_zabbix_state_get_tx_count, + get_tx: rs_zabbix_state_get_tx, + + // unidirectional, always complete after creation + tx_comp_st_ts: 1, + tx_comp_st_tc: 1, + tx_get_progress: rs_zabbix_tx_get_alstate_progress, + + get_eventinfo: Some(ZabbixEvent::get_event_info), + get_eventinfo_byid: Some(ZabbixEvent::get_event_info_by_id), + + localstorage_new: None, + localstorage_free: None, + get_tx_files: None, + + get_tx_iterator: Some(zabbix_get_tx_iterator), + get_tx_data: rs_zabbix_get_tx_data, + get_state_data: rs_zabbix_get_state_data, + apply_tx_config: None, + flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS, + get_frame_id_by_name: Some(ZabbixFrameType::ffi_id_from_name), + get_frame_name_by_id: Some(ZabbixFrameType::ffi_name_from_id), + }; + + let ip_proto_str = CString::new("tcp").unwrap(); + ALPROTO_FAILED = StringToAppProto("failed\0".as_ptr()); + + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { + let alproto = AppLayerRegisterProtocolDetection(&parser, 1); + ALPROTO_ZABBIX = alproto; + if AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, + ALPROTO_ZABBIX, + b"ZBXD\0".as_ptr() as *const std::os::raw::c_char, + 4, + 0, + Direction::ToServer as u8, + ) < 0 + { + SCLog!(Level::Warning, "Rust zabbix failed to register detection."); + } + + if AppLayerProtoDetectPMRegisterPatternCS( + IPPROTO_TCP, + ALPROTO_ZABBIX, + b"ZBXD\0".as_ptr() as *const std::os::raw::c_char, + 4, + 0, + Direction::ToClient as u8, + ) < 0 + { + SCLog!(Level::Warning, "Rust zabbix failed to register detection."); + } + + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { + let _ = AppLayerRegisterParser(&parser, alproto); + } + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_ZABBIX); + SCLog!(Level::Notice, "Rust zabbix parser registered."); + } else { + SCLog!( + Level::Notice, + "Protocol detector and parser disabled for zabbix." + ); + } +} diff --git a/examples/plugins/zabbix/zabbix.rules b/examples/plugins/zabbix/zabbix.rules new file mode 100644 index 000000000000..407a82e4d39f --- /dev/null +++ b/examples/plugins/zabbix/zabbix.rules @@ -0,0 +1,3 @@ +alert zabbix any any -> any any (msg: "zabbix frame"; frame: zabbix.data; content: "proc"; startswith; sid:10;) +alert zabbix any any -> any any (msg: "zabbix payload"; zabbix.data; content: "proc"; startswith; sid:11;) +alert zabbix any any -> any any (msg: "zabbix flags"; zabbix.flags: &1=1; sid:12;) diff --git a/examples/plugins/zabbix/zabbix.yaml b/examples/plugins/zabbix/zabbix.yaml new file mode 100644 index 000000000000..4c699773b6c5 --- /dev/null +++ b/examples/plugins/zabbix/zabbix.yaml @@ -0,0 +1,20 @@ +%YAML 1.1 +--- + +outputs: + - eve-log: + enabled: true + types: + - alert + - anomaly + - files + - flow + - stats: + enabled: no + - zabbix: + enabled: yes + +app-layer: + protocols: + zabbix: + enabled: true diff --git a/rust/src/core.rs b/rust/src/core.rs index a628b300384a..8dafc73eec81 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -109,7 +109,7 @@ impl From for u8 { pub type AppProto = u16; pub const ALPROTO_UNKNOWN : AppProto = 0; -pub static mut ALPROTO_FAILED : AppProto = 0; // updated during init +pub const ALPROTO_FAILED : AppProto = 1; pub const IPPROTO_TCP : u8 = 6; pub const IPPROTO_UDP : u8 = 17; @@ -252,7 +252,6 @@ pub fn init_ffi(context: &'static SuricataContext) { unsafe { SC = Some(context); - ALPROTO_FAILED = StringToAppProto("failed\0".as_ptr()); } } diff --git a/rust/src/ldap/ldap.rs b/rust/src/ldap/ldap.rs index f86c8d8499d9..80cf084a3540 100644 --- a/rust/src/ldap/ldap.rs +++ b/rust/src/ldap/ldap.rs @@ -499,7 +499,7 @@ fn probe(input: &[u8], direction: Direction, rdir: *mut u8) -> AppProto { Ok((_, msg)) => { let ldap_msg = LdapMessage::from(msg); if ldap_msg.is_unknown() { - return unsafe { ALPROTO_FAILED }; + return ALPROTO_FAILED; } if direction == Direction::ToServer && !ldap_msg.is_request() { unsafe { @@ -517,7 +517,7 @@ fn probe(input: &[u8], direction: Direction, rdir: *mut u8) -> AppProto { return ALPROTO_UNKNOWN; } Err(_e) => { - return unsafe { ALPROTO_FAILED }; + return ALPROTO_FAILED; } } } diff --git a/rust/src/modbus/modbus.rs b/rust/src/modbus/modbus.rs index 0d0c73371ef0..9401fc6922d0 100644 --- a/rust/src/modbus/modbus.rs +++ b/rust/src/modbus/modbus.rs @@ -281,7 +281,7 @@ pub extern "C" fn rs_modbus_probe( match MODBUS_PARSER.probe(slice, Direction::Unknown) { Status::Recognized => unsafe { ALPROTO_MODBUS }, Status::Incomplete => ALPROTO_UNKNOWN, - Status::Unrecognized => unsafe { ALPROTO_FAILED }, + Status::Unrecognized => ALPROTO_FAILED, } } diff --git a/rust/src/ntp/ntp.rs b/rust/src/ntp/ntp.rs index ae723bbb21cd..e17648c4c960 100644 --- a/rust/src/ntp/ntp.rs +++ b/rust/src/ntp/ntp.rs @@ -259,7 +259,7 @@ pub extern "C" fn ntp_probing_parser(_flow: *const Flow, return ALPROTO_UNKNOWN; }, Err(_) => { - return unsafe{ALPROTO_FAILED}; + return ALPROTO_FAILED; }, } } diff --git a/rust/src/sip/sip.rs b/rust/src/sip/sip.rs index 1a73d4e46a66..5f52e0c8db07 100755 --- a/rust/src/sip/sip.rs +++ b/rust/src/sip/sip.rs @@ -496,7 +496,6 @@ fn register_pattern_probe(proto: u8) -> i8 { "ACK\0", "BYE\0", "CANCEL\0", - "UPDATE\0", "REFER\0", "PRACK\0", "SUBSCRIBE\0", @@ -526,6 +525,16 @@ fn register_pattern_probe(proto: u8) -> i8 { 0, core::Direction::ToClient as u8, ); + if proto == core::IPPROTO_UDP { + r |= AppLayerProtoDetectPMRegisterPatternCS( + proto, + ALPROTO_SIP, + "UPDATE\0".as_ptr() as *const std::os::raw::c_char, + "UPDATE".len() as u16, + 0, + core::Direction::ToServer as u8, + ); + } } if r == 0 { diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 901ed2a23927..c9471c34f603 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -2154,7 +2154,7 @@ fn smb_probe_tcp(flags: u8, slice: &[u8], rdir: *mut u8, begins: bool) -> AppPro } } SCLogDebug!("no smb"); - unsafe { return ALPROTO_FAILED; } + return ALPROTO_FAILED; } // probing confirmation parser diff --git a/scripts/setup-app-layer.py b/scripts/setup-app-layer.py index bb3d23e83944..f94e68ae7d7e 100755 --- a/scripts/setup-app-layer.py +++ b/scripts/setup-app-layer.py @@ -129,7 +129,7 @@ def patch_app_layer_protos_h(protoname): open(filename, "w").write(output.getvalue()) def patch_app_layer_protos_c(protoname): - filename = "src/app-layer-protos.c" + filename = "src/app-layer.c" print("Patching %s." % (filename)) output = io.StringIO() diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index a65a98c88a41..dbf6eb0b55e8 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -67,8 +67,6 @@ typedef struct AppLayerProtoDetectProbingParserElement_ { AppProto alproto; - /* \todo calculate at runtime and get rid of this var */ - uint32_t alproto_mask; /* the min length of data that has to be supplied to invoke the parser */ uint16_t min_depth; /* the max length of data after which this parser won't be invoked */ @@ -90,8 +88,6 @@ typedef struct AppLayerProtoDetectProbingParserPort_ { // WebSocket has this set to false as it only works with protocol change bool use_ports; - uint32_t alproto_mask; - /* the max depth for all the probing parsers registered for this port */ uint16_t dp_max_depth; uint16_t sp_max_depth; @@ -158,8 +154,15 @@ typedef struct AppLayerProtoDetectCtx_ { /* Indicates the protocols that have registered themselves * for protocol detection. This table is independent of the - * ipproto. */ - const char *alproto_names[ALPROTO_MAX]; + * ipproto. It should be allocated to contain ALPROTO_MAX + * protocols. */ + const char **alproto_names; + + /* Protocol expectations, like ftp-data on tcp. + * It should be allocated to contain ALPROTO_MAX + * app-layer protocols. For each protocol, an iptype + * is referenced (or 0 if there is no expectation). */ + uint8_t *expectation_proto; } AppLayerProtoDetectCtx; typedef struct AppLayerProtoDetectAliases_ { @@ -285,7 +288,7 @@ static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx, } /* alproto bit field */ - uint8_t pm_results_bf[(ALPROTO_MAX / 8) + 1]; + uint8_t pm_results_bf[(AlprotoMax / 8) + 1]; memset(pm_results_bf, 0, sizeof(pm_results_bf)); /* loop through unique pattern id's. Can't use search_cnt here, @@ -317,7 +320,7 @@ static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx, /** \internal * \brief Run Pattern Sigs against buffer * \param direction direction for the patterns - * \param pm_results[out] AppProto array of size ALPROTO_MAX */ + * \param pm_results[out] AppProto array of size AlprotoMax */ static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f, const uint8_t *buf, uint32_t buflen, uint8_t flags, AppProto *pm_results, bool *rflow) { @@ -473,11 +476,20 @@ static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t flags) } static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement *pe, Flow *f, - uint8_t flags, const uint8_t *buf, uint32_t buflen, uint32_t *alproto_masks, uint8_t *rdir) + uint8_t flags, const uint8_t *buf, uint32_t buflen, uint32_t *alproto_masks, uint8_t *rdir, + uint8_t *nb_tried) { while (pe != NULL) { - if ((buflen < pe->min_depth) || - (alproto_masks[0] & pe->alproto_mask)) { + // callers make alproto_masks and nb_tried are either both defined or both NULL + if (alproto_masks != NULL) { + DEBUG_VALIDATE_BUG_ON(*nb_tried >= 32); + if (buflen < pe->min_depth || (alproto_masks[0] & BIT_U32(*nb_tried))) { + // skip if already failed once + pe = pe->next; + *nb_tried = *nb_tried + 1; + continue; + } + } else if (buflen < pe->min_depth) { pe = pe->next; continue; } @@ -491,9 +503,12 @@ static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement if (AppProtoIsValid(alproto)) { SCReturnUInt(alproto); } - if (alproto == ALPROTO_FAILED || - (pe->max_depth != 0 && buflen > pe->max_depth)) { - alproto_masks[0] |= pe->alproto_mask; + if (alproto_masks != NULL) { + if ((alproto == ALPROTO_FAILED || (pe->max_depth != 0 && buflen > pe->max_depth))) { + // This PE failed, mask it from now on + alproto_masks[0] |= BIT_U32(*nb_tried); + } + *nb_tried = *nb_tried + 1; } pe = pe->next; } @@ -517,8 +532,20 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 const AppLayerProtoDetectProbingParserElement *pe1 = NULL; const AppLayerProtoDetectProbingParserElement *pe2 = NULL; AppProto alproto = ALPROTO_UNKNOWN; + // number of tried protocols : + // used against alproto_masks to see if al tried protocols failed + // Instead of keeping a bitmask for all protocols, we + // use only the protocols relevant to this flow, so as to + // have alproto_masks a u32 but we have more than 32 alprotos + // in Suricata, but we do not allow more than 32 probing parsers + // on one flow. + // alproto_masks is consistent throughout different calls here + // from different packets in the flow. + // We can have up to 4 calls to PPGetProto with a mask : + // destination port (probing parser), source port, + // and again with the reversed flow in case of midstream. + uint8_t nb_tried = 0; uint32_t *alproto_masks = NULL; - uint32_t mask = 0; uint8_t idir = (flags & (STREAM_TOSERVER | STREAM_TOCLIENT)); uint8_t dir = idir; uint16_t dp = f->protodetect_dp ? f->protodetect_dp : FLOW_GET_DP(f); @@ -600,34 +627,30 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint3 /* run the parser(s): always call with original direction */ uint8_t rdir = 0; - alproto = PPGetProto(pe0, f, flags, buf, buflen, alproto_masks, &rdir); + // pe0 can change based on the flow state, do not use mask for it + alproto = PPGetProto(pe0, f, flags, buf, buflen, NULL, &rdir, NULL); if (AppProtoIsValid(alproto)) goto end; - alproto = PPGetProto(pe1, f, flags, buf, buflen, alproto_masks, &rdir); + alproto = PPGetProto(pe1, f, flags, buf, buflen, alproto_masks, &rdir, &nb_tried); if (AppProtoIsValid(alproto)) goto end; - alproto = PPGetProto(pe2, f, flags, buf, buflen, alproto_masks, &rdir); + alproto = PPGetProto(pe2, f, flags, buf, buflen, alproto_masks, &rdir, &nb_tried); if (AppProtoIsValid(alproto)) goto end; /* get the mask we need for this direction */ if (dir == idir) { - if (pp_port_dp && pp_port_sp) - mask = pp_port_dp->alproto_mask|pp_port_sp->alproto_mask; - else if (pp_port_dp) - mask = pp_port_dp->alproto_mask; - else if (pp_port_sp) - mask = pp_port_sp->alproto_mask; - - if (alproto_masks[0] == mask) { + // if we tried 3 protocols, we set probing parsing done if + // alproto_masks[0] = 7 = 0b111 = BIT_U32(3) - 1 = 1<<3 - 1 + if (alproto_masks[0] == BIT_U32(nb_tried) - 1) { FLOW_SET_PP_DONE(f, dir); SCLogDebug("%s, mask is now %08x, needed %08x, so done", - (dir == STREAM_TOSERVER) ? "toserver":"toclient", - alproto_masks[0], mask); + (dir == STREAM_TOSERVER) ? "toserver" : "toclient", alproto_masks[0], + BIT_U32(nb_tried) - 1); } else { SCLogDebug("%s, mask is now %08x, need %08x", - (dir == STREAM_TOSERVER) ? "toserver":"toclient", - alproto_masks[0], mask); + (dir == STREAM_TOSERVER) ? "toserver" : "toclient", alproto_masks[0], + BIT_U32(nb_tried) - 1); } } @@ -683,17 +706,6 @@ static void AppLayerProtoDetectPPGetIpprotos(AppProto alproto, SCReturn; } -static uint32_t AppLayerProtoDetectProbingParserGetMask(AppProto alproto) -{ - SCEnter(); - - if (!(alproto > ALPROTO_UNKNOWN && alproto < ALPROTO_FAILED)) { - FatalError("Unknown protocol detected - %u", alproto); - } - - SCReturnUInt(BIT_U32(alproto)); -} - static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParserElementAlloc(void) { SCEnter(); @@ -787,7 +799,6 @@ static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParser AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc(); pe->alproto = alproto; - pe->alproto_mask = AppLayerProtoDetectProbingParserGetMask(alproto); pe->min_depth = min_depth; pe->max_depth = max_depth; pe->next = NULL; @@ -797,7 +808,7 @@ static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParser "register the probing parser. min_depth >= max_depth"); goto error; } - if (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_MAX) { + if (alproto <= ALPROTO_UNKNOWN || alproto >= AlprotoMax) { SCLogError("Invalid arguments sent to register " "the probing parser. Invalid alproto - %d", alproto); @@ -818,7 +829,6 @@ AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParse AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementAlloc(); new_pe->alproto = pe->alproto; - new_pe->alproto_mask = pe->alproto_mask; new_pe->min_depth = pe->min_depth; new_pe->max_depth = pe->max_depth; new_pe->ProbingParserTs = pe->ProbingParserTs; @@ -852,15 +862,12 @@ static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingPar if (pp_port->dp != NULL) { printf(" Port: %"PRIu16 "\n", pp_port->port); - printf(" Destination port: (max-depth: %"PRIu16 ", " - "mask - %"PRIu32")\n", - pp_port->dp_max_depth, - pp_port->alproto_mask); + printf(" Destination port: (max-depth: %" PRIu16 ")\n", + pp_port->dp_max_depth); pp_pe = pp_port->dp; for ( ; pp_pe != NULL; pp_pe = pp_pe->next) { printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto)); - printf(" mask: %"PRIu32 "\n", pp_pe->alproto_mask); printf(" min_depth: %"PRIu32 "\n", pp_pe->min_depth); printf(" max_depth: %"PRIu32 "\n", pp_pe->max_depth); @@ -872,15 +879,11 @@ static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingPar continue; } - printf(" Source port: (max-depth: %"PRIu16 ", " - "mask - %"PRIu32")\n", - pp_port->sp_max_depth, - pp_port->alproto_mask); + printf(" Source port: (max-depth: %" PRIu16 ")\n", pp_port->sp_max_depth); pp_pe = pp_port->sp; for ( ; pp_pe != NULL; pp_pe = pp_pe->next) { printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto)); - printf(" mask: %"PRIu32 "\n", pp_pe->alproto_mask); printf(" min_depth: %"PRIu32 "\n", pp_pe->min_depth); printf(" max_depth: %"PRIu32 "\n", pp_pe->max_depth); @@ -1023,7 +1026,6 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppLayerProtoDetectProbingParserElement *dup_pe = AppLayerProtoDetectProbingParserElementDuplicate(zero_pe); AppLayerProtoDetectProbingParserElementAppend(&curr_port->dp, dup_pe); - curr_port->alproto_mask |= dup_pe->alproto_mask; } zero_pe = zero_port->sp; @@ -1040,7 +1042,6 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing AppLayerProtoDetectProbingParserElement *dup_pe = AppLayerProtoDetectProbingParserElementDuplicate(zero_pe); AppLayerProtoDetectProbingParserElementAppend(&curr_port->sp, dup_pe); - curr_port->alproto_mask |= dup_pe->alproto_mask; } } /* if (zero_port != NULL) */ } /* if (curr_port == NULL) */ @@ -1081,7 +1082,6 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port->dp_max_depth < new_pe->max_depth) { curr_port->dp_max_depth = new_pe->max_depth; } - curr_port->alproto_mask |= new_pe->alproto_mask; head_pe = &curr_port->dp; } else { curr_pe->ProbingParserTs = ProbingParser2; @@ -1094,7 +1094,6 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing curr_port->sp_max_depth < new_pe->max_depth) { curr_port->sp_max_depth = new_pe->max_depth; } - curr_port->alproto_mask |= new_pe->alproto_mask; head_pe = &curr_port->sp; } AppLayerProtoDetectProbingParserElementAppend(head_pe, new_pe); @@ -1112,9 +1111,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing temp_port->dp_max_depth < curr_pe->max_depth) { temp_port->dp_max_depth = curr_pe->max_depth; } - AppLayerProtoDetectProbingParserElementAppend(&temp_port->dp, - AppLayerProtoDetectProbingParserElementDuplicate(curr_pe)); - temp_port->alproto_mask |= curr_pe->alproto_mask; + AppLayerProtoDetectProbingParserElementAppend( + &temp_port->dp, AppLayerProtoDetectProbingParserElementDuplicate(curr_pe)); } else { if (temp_port->sp == NULL) temp_port->sp_max_depth = curr_pe->max_depth; @@ -1124,9 +1122,8 @@ static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbing temp_port->sp_max_depth < curr_pe->max_depth) { temp_port->sp_max_depth = curr_pe->max_depth; } - AppLayerProtoDetectProbingParserElementAppend(&temp_port->sp, - AppLayerProtoDetectProbingParserElementDuplicate(curr_pe)); - temp_port->alproto_mask |= curr_pe->alproto_mask; + AppLayerProtoDetectProbingParserElementAppend( + &temp_port->sp, AppLayerProtoDetectProbingParserElementDuplicate(curr_pe)); } temp_port = temp_port->next; } /* while */ @@ -1404,7 +1401,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f AppProto pm_alproto = ALPROTO_UNKNOWN; if (!FLOW_IS_PM_DONE(f, flags)) { - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; uint16_t pm_matches = AppLayerProtoDetectPMGetProto( tctx, f, buf, buflen, flags, pm_results, reverse_flow); if (pm_matches > 0) { @@ -1718,6 +1715,15 @@ int AppLayerProtoDetectSetup(void) } } + alpd_ctx.alproto_names = SCCalloc(AlprotoMax, sizeof(char *)); + if (unlikely(alpd_ctx.alproto_names == NULL)) { + FatalError("Unable to alloc alproto_names."); + } + // to realloc when dynamic protos are added + alpd_ctx.expectation_proto = SCCalloc(AlprotoMax, sizeof(uint8_t)); + if (unlikely(alpd_ctx.expectation_proto == NULL)) { + FatalError("Unable to alloc expectation_proto."); + } AppLayerExpectationSetup(); SCReturnInt(0); @@ -1749,6 +1755,11 @@ int AppLayerProtoDetectDeSetup(void) } } + SCFree(alpd_ctx.alproto_names); + alpd_ctx.alproto_names = NULL; + SCFree(alpd_ctx.expectation_proto); + alpd_ctx.expectation_proto = NULL; + SpmDestroyGlobalThreadCtx(alpd_ctx.spm_global_thread_ctx); AppLayerProtoDetectFreeAliases(); @@ -1762,6 +1773,7 @@ void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_n { SCEnter(); + // should have just been realloced when dynamic protos is added if (alpd_ctx.alproto_names[alproto] == NULL) alpd_ctx.alproto_names[alproto] = alproto_name; @@ -2068,7 +2080,7 @@ AppProto AppLayerProtoDetectGetProtoByName(const char *alproto_name) AppProto a; AppProto b = StringToAppProto(alproto_name); - for (a = 0; a < ALPROTO_MAX; a++) { + for (a = 0; a < AlprotoMax; a++) { if (alpd_ctx.alproto_names[a] != NULL && AppProtoEquals(b, a)) { // That means return HTTP_ANY if HTTP1 or HTTP2 is enabled SCReturnCT(b, "AppProto"); @@ -2099,11 +2111,11 @@ void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos) { SCEnter(); - memset(alprotos, 0, ALPROTO_MAX * sizeof(AppProto)); + memset(alprotos, 0, AlprotoMax * sizeof(AppProto)); int alproto; - for (alproto = 0; alproto != ALPROTO_MAX; alproto++) { + for (alproto = 0; alproto != AlprotoMax; alproto++) { if (alpd_ctx.alproto_names[alproto] != NULL) alprotos[alproto] = 1; } @@ -2111,27 +2123,25 @@ void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos) SCReturn; } -uint8_t expectation_proto[ALPROTO_MAX]; - static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto, uint8_t *ipprotos) { - if (expectation_proto[alproto] == IPPROTO_TCP) { + if (alpd_ctx.expectation_proto[alproto] == IPPROTO_TCP) { ipprotos[IPPROTO_TCP / 8] |= 1 << (IPPROTO_TCP % 8); } - if (expectation_proto[alproto] == IPPROTO_UDP) { + if (alpd_ctx.expectation_proto[alproto] == IPPROTO_UDP) { ipprotos[IPPROTO_UDP / 8] |= 1 << (IPPROTO_UDP % 8); } } void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto) { - if (expectation_proto[alproto]) { - if (proto != expectation_proto[alproto]) { + if (alpd_ctx.expectation_proto[alproto]) { + if (proto != alpd_ctx.expectation_proto[alproto]) { SCLogError("Expectation on 2 IP protocols are not supported"); } } - expectation_proto[alproto] = proto; + alpd_ctx.expectation_proto[alproto] = proto; } /***** Unittests *****/ @@ -2209,7 +2219,7 @@ static int AppLayerProtoDetectTest03(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2256,7 +2266,7 @@ static int AppLayerProtoDetectTest04(void) uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; Flow f; memset(&f, 0x00, sizeof(f)); - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); @@ -2294,7 +2304,7 @@ static int AppLayerProtoDetectTest05(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\nBlahblah"; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2338,7 +2348,7 @@ static int AppLayerProtoDetectTest06(void) AppLayerProtoDetectSetup(); uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n"; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2384,7 +2394,7 @@ static int AppLayerProtoDetectTest07(void) Flow f; memset(&f, 0x00, sizeof(f)); f.protomap = FlowGetProtoMapping(IPPROTO_TCP); - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); const char *buf = "HTTP"; @@ -2438,7 +2448,7 @@ static int AppLayerProtoDetectTest08(void) 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00 }; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2493,7 +2503,7 @@ static int AppLayerProtoDetectTest09(void) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02 }; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2543,7 +2553,7 @@ static int AppLayerProtoDetectTest10(void) 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2588,7 +2598,7 @@ static int AppLayerProtoDetectTest11(void) uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; memset(pm_results, 0, sizeof(pm_results)); Flow f; memset(&f, 0x00, sizeof(f)); @@ -2713,7 +2723,7 @@ static int AppLayerProtoDetectTest13(void) uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; Flow f; memset(&f, 0x00, sizeof(f)); @@ -2784,7 +2794,7 @@ static int AppLayerProtoDetectTest14(void) uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n"; uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n"; - AppProto pm_results[ALPROTO_MAX]; + AppProto pm_results[AlprotoMax]; uint32_t cnt; Flow f; memset(&f, 0x00, sizeof(f)); @@ -2850,14 +2860,12 @@ typedef struct AppLayerProtoDetectPPTestDataElement_ { const char *alproto_name; AppProto alproto; uint16_t port; - uint32_t alproto_mask; uint32_t min_depth; uint32_t max_depth; } AppLayerProtoDetectPPTestDataElement; typedef struct AppLayerProtoDetectPPTestDataPort_ { uint16_t port; - uint32_t alproto_mask; uint16_t dp_max_depth; uint16_t sp_max_depth; @@ -2892,10 +2900,6 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, for (k = 0; k < ip_proto[i].no_of_port; k++, pp_port = pp_port->next) { if (pp_port->port != ip_proto[i].port[k].port) goto end; - if (pp_port->alproto_mask != ip_proto[i].port[k].alproto_mask) - goto end; - if (pp_port->alproto_mask != ip_proto[i].port[k].alproto_mask) - goto end; if (pp_port->dp_max_depth != ip_proto[i].port[k].dp_max_depth) goto end; if (pp_port->sp_max_depth != ip_proto[i].port[k].sp_max_depth) @@ -2911,9 +2915,6 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, if (pp_element->alproto != ip_proto[i].port[k].toserver_element[j].alproto) { goto end; } - if (pp_element->alproto_mask != ip_proto[i].port[k].toserver_element[j].alproto_mask) { - goto end; - } if (pp_element->min_depth != ip_proto[i].port[k].toserver_element[j].min_depth) { goto end; } @@ -2932,9 +2933,6 @@ static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp, if (pp_element->alproto != ip_proto[i].port[k].toclient_element[j].alproto) { goto end; } - if (pp_element->alproto_mask != ip_proto[i].port[k].toclient_element[j].alproto_mask) { - goto end; - } if (pp_element->min_depth != ip_proto[i].port[k].toclient_element[j].min_depth) { goto end; } @@ -3106,100 +3104,76 @@ static int AppLayerProtoDetectTest15(void) ProbingParserDummyForTesting, NULL); AppLayerProtoDetectPPTestDataElement element_ts_80[] = { - { "http", ALPROTO_HTTP1, 80, 1 << ALPROTO_HTTP1, 5, 8 }, - { "smb", ALPROTO_SMB, 80, 1 << ALPROTO_SMB, 5, 6 }, - { "ftp", ALPROTO_FTP, 80, 1 << ALPROTO_FTP, 7, 10 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, + { "http", ALPROTO_HTTP1, 80, 5, 8 }, + { "smb", ALPROTO_SMB, 80, 5, 6 }, + { "ftp", ALPROTO_FTP, 80, 7, 10 }, + { "smtp", ALPROTO_SMTP, 0, 12, 0 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "irc", ALPROTO_IRC, 0, 12, 25 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, }; - AppLayerProtoDetectPPTestDataElement element_tc_80[] = { { "http", ALPROTO_HTTP1, 80, - 1 << ALPROTO_HTTP1, 5, 8 }, - { "smb", ALPROTO_SMB, 80, 1 << ALPROTO_SMB, 5, 6 }, - { "ftp", ALPROTO_FTP, 80, 1 << ALPROTO_FTP, 7, 10 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 } }; + AppLayerProtoDetectPPTestDataElement element_tc_80[] = { { "http", ALPROTO_HTTP1, 80, 5, 8 }, + { "smb", ALPROTO_SMB, 80, 5, 6 }, { "ftp", ALPROTO_FTP, 80, 7, 10 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, { "irc", ALPROTO_IRC, 0, 12, 14 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, { "smtp", ALPROTO_SMTP, 0, 12, 17 } }; AppLayerProtoDetectPPTestDataElement element_ts_81[] = { - { "dcerpc", ALPROTO_DCERPC, 81, 1 << ALPROTO_DCERPC, 9, 10 }, - { "ftp", ALPROTO_FTP, 81, 1 << ALPROTO_FTP, 7, 15 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - }; - AppLayerProtoDetectPPTestDataElement element_tc_81[] = { - { "ftp", ALPROTO_FTP, 81, 1 << ALPROTO_FTP, 7, 15 }, - { "dcerpc", ALPROTO_DCERPC, 81, 1 << ALPROTO_DCERPC, 9, 10 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 } - }; + { "dcerpc", ALPROTO_DCERPC, 81, 9, 10 }, + { "ftp", ALPROTO_FTP, 81, 7, 15 }, + { "smtp", ALPROTO_SMTP, 0, 12, 0 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "irc", ALPROTO_IRC, 0, 12, 25 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, + }; + AppLayerProtoDetectPPTestDataElement element_tc_81[] = { { "ftp", ALPROTO_FTP, 81, 7, 15 }, + { "dcerpc", ALPROTO_DCERPC, 81, 9, 10 }, { "jabber", ALPROTO_JABBER, 0, 12, 23 }, + { "irc", ALPROTO_IRC, 0, 12, 14 }, { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "smtp", ALPROTO_SMTP, 0, 12, 17 } }; AppLayerProtoDetectPPTestDataElement element_ts_85[] = { - { "dcerpc", ALPROTO_DCERPC, 85, 1 << ALPROTO_DCERPC, 9, 10 }, - { "ftp", ALPROTO_FTP, 85, 1 << ALPROTO_FTP, 7, 15 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - }; - AppLayerProtoDetectPPTestDataElement element_tc_85[] = { - { "dcerpc", ALPROTO_DCERPC, 85, 1 << ALPROTO_DCERPC, 9, 10 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 } - }; + { "dcerpc", ALPROTO_DCERPC, 85, 9, 10 }, + { "ftp", ALPROTO_FTP, 85, 7, 15 }, + { "smtp", ALPROTO_SMTP, 0, 12, 0 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "irc", ALPROTO_IRC, 0, 12, 25 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, + }; + AppLayerProtoDetectPPTestDataElement element_tc_85[] = { { "dcerpc", ALPROTO_DCERPC, 85, 9, + 10 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, { "irc", ALPROTO_IRC, 0, 12, 14 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, { "smtp", ALPROTO_SMTP, 0, 12, 17 } }; AppLayerProtoDetectPPTestDataElement element_ts_90[] = { - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - }; - AppLayerProtoDetectPPTestDataElement element_tc_90[] = { - { "ftp", ALPROTO_FTP, 90, 1 << ALPROTO_FTP, 7, 15 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 } - }; + { "smtp", ALPROTO_SMTP, 0, 12, 0 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "irc", ALPROTO_IRC, 0, 12, 25 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, + }; + AppLayerProtoDetectPPTestDataElement element_tc_90[] = { { "ftp", ALPROTO_FTP, 90, 7, 15 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, { "irc", ALPROTO_IRC, 0, 12, 14 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, { "smtp", ALPROTO_SMTP, 0, 12, 17 } }; AppLayerProtoDetectPPTestDataElement element_ts_0[] = { - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 }, - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - }; - AppLayerProtoDetectPPTestDataElement element_tc_0[] = { - { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 }, - { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 }, - { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 }, - { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 } - }; - + { "smtp", ALPROTO_SMTP, 0, 12, 0 }, + { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "irc", ALPROTO_IRC, 0, 12, 25 }, + { "jabber", ALPROTO_JABBER, 0, 12, 23 }, + }; + AppLayerProtoDetectPPTestDataElement element_tc_0[] = { { "jabber", ALPROTO_JABBER, 0, 12, 23 }, + { "irc", ALPROTO_IRC, 0, 12, 14 }, { "tls", ALPROTO_TLS, 0, 12, 18 }, + { "smtp", ALPROTO_SMTP, 0, 12, 17 } }; AppLayerProtoDetectPPTestDataElement element_ts_85_udp[] = { - { "imap", ALPROTO_IMAP, 85, 1 << ALPROTO_IMAP, 12, 23 }, - }; + { "imap", ALPROTO_IMAP, 85, 12, 23 }, + }; AppLayerProtoDetectPPTestDataElement element_tc_85_udp[] = { - { "imap", ALPROTO_IMAP, 85, 1 << ALPROTO_IMAP, 12, 23 }, - }; + { "imap", ALPROTO_IMAP, 85, 12, 23 }, + }; AppLayerProtoDetectPPTestDataPort ports_tcp[] = { { 80, - ((1 << ALPROTO_HTTP1) | (1 << ALPROTO_SMB) | (1 << ALPROTO_FTP) | - (1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | - (1 << ALPROTO_JABBER)), - ((1 << ALPROTO_HTTP1) | (1 << ALPROTO_SMB) | (1 << ALPROTO_FTP) | - (1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) | (1 << ALPROTO_TLS) | - (1 << ALPROTO_SMTP)), + 23, 23, element_ts_80, element_tc_80, @@ -3208,52 +3182,35 @@ static int AppLayerProtoDetectTest15(void) }, { 81, - ((1 << ALPROTO_DCERPC) | (1 << ALPROTO_FTP) | (1 << ALPROTO_SMTP) | - (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | (1 << ALPROTO_JABBER)), - ((1 << ALPROTO_FTP) | (1 << ALPROTO_DCERPC) | (1 << ALPROTO_JABBER) | - (1 << ALPROTO_IRC) | (1 << ALPROTO_TLS) | (1 << ALPROTO_SMTP)), + 23, 23, element_ts_81, element_tc_81, sizeof(element_ts_81) / sizeof(AppLayerProtoDetectPPTestDataElement), sizeof(element_tc_81) / sizeof(AppLayerProtoDetectPPTestDataElement), }, - { 85, - ((1 << ALPROTO_DCERPC) | (1 << ALPROTO_FTP) | (1 << ALPROTO_SMTP) | - (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | (1 << ALPROTO_JABBER)), - ((1 << ALPROTO_DCERPC) | (1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) | - (1 << ALPROTO_TLS) | (1 << ALPROTO_SMTP)), - 23, element_ts_85, element_tc_85, + { 85, 23, 23, element_ts_85, element_tc_85, sizeof(element_ts_85) / sizeof(AppLayerProtoDetectPPTestDataElement), sizeof(element_tc_85) / sizeof(AppLayerProtoDetectPPTestDataElement) }, - { 90, - ((1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | - (1 << ALPROTO_JABBER)), - ((1 << ALPROTO_FTP) | (1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) | - (1 << ALPROTO_TLS) | (1 << ALPROTO_SMTP)), - 23, element_ts_90, element_tc_90, + { 90, 23, 23, element_ts_90, element_tc_90, sizeof(element_ts_90) / sizeof(AppLayerProtoDetectPPTestDataElement), sizeof(element_tc_90) / sizeof(AppLayerProtoDetectPPTestDataElement) }, - { 0, - ((1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | - (1 << ALPROTO_JABBER)), - ((1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) | (1 << ALPROTO_TLS) | - (1 << ALPROTO_SMTP)), - 23, element_ts_0, element_tc_0, + { 0, 23, 23, element_ts_0, element_tc_0, sizeof(element_ts_0) / sizeof(AppLayerProtoDetectPPTestDataElement), sizeof(element_tc_0) / sizeof(AppLayerProtoDetectPPTestDataElement) } }; AppLayerProtoDetectPPTestDataPort ports_udp[] = { - { 85, - (1 << ALPROTO_IMAP), - (1 << ALPROTO_IMAP), - 23, - element_ts_85_udp, element_tc_85_udp, - sizeof(element_ts_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement), - sizeof(element_tc_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement), - }, - }; + { + 85, + 23, + 23, + element_ts_85_udp, + element_tc_85_udp, + sizeof(element_ts_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement), + sizeof(element_tc_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement), + }, + }; AppLayerProtoDetectPPTestDataIPProto ip_proto[] = { { IPPROTO_TCP, diff --git a/src/app-layer-frames.c b/src/app-layer-frames.c index 432bd020d230..0ba738f8b19f 100644 --- a/src/app-layer-frames.c +++ b/src/app-layer-frames.c @@ -33,19 +33,29 @@ struct FrameConfig { SC_ATOMIC_DECLARE(uint64_t, types); }; -static struct FrameConfig frame_config[ALPROTO_MAX]; +/* This array should be allocated to contain AlprotoMax protocols. */ +static struct FrameConfig *frame_config; void FrameConfigInit(void) { - for (AppProto p = 0; p < ALPROTO_MAX; p++) { + frame_config = SCCalloc(AlprotoMax, sizeof(struct FrameConfig)); + if (unlikely(frame_config == NULL)) { + FatalError("Unable to alloc frame_config."); + } + for (AppProto p = 0; p < AlprotoMax; p++) { SC_ATOMIC_INIT(frame_config[p].types); } } +void FrameConfigDeInit(void) +{ + SCFree(frame_config); +} + void FrameConfigEnableAll(void) { const uint64_t bits = UINT64_MAX; - for (AppProto p = 0; p < ALPROTO_MAX; p++) { + for (AppProto p = 0; p < AlprotoMax; p++) { struct FrameConfig *fc = &frame_config[p]; SC_ATOMIC_OR(fc->types, bits); } diff --git a/src/app-layer-frames.h b/src/app-layer-frames.h index f49bead57b41..f1d5135d8953 100644 --- a/src/app-layer-frames.h +++ b/src/app-layer-frames.h @@ -106,6 +106,7 @@ FramesContainer *AppLayerFramesGetContainer(Flow *f); FramesContainer *AppLayerFramesSetupContainer(Flow *f); void FrameConfigInit(void); +void FrameConfigDeInit(void); void FrameConfigEnableAll(void); void FrameConfigEnable(const AppProto p, const uint8_t type); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index d1cacc572f40..4bf99cf9196c 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -56,7 +56,7 @@ #include "app-layer-imap.h" struct AppLayerParserThreadCtx_ { - void *alproto_local_storage[FLOW_PROTO_MAX][ALPROTO_MAX]; + void *(*alproto_local_storage)[FLOW_PROTO_MAX]; }; @@ -123,7 +123,7 @@ typedef struct AppLayerParserProtoCtx_ } AppLayerParserProtoCtx; typedef struct AppLayerParserCtx_ { - AppLayerParserProtoCtx ctxs[FLOW_PROTO_MAX][ALPROTO_MAX]; + AppLayerParserProtoCtx (*ctxs)[FLOW_PROTO_MAX]; } AppLayerParserCtx; struct AppLayerParserState_ { @@ -218,7 +218,7 @@ int AppLayerParserProtoIsRegistered(uint8_t ipproto, AppProto alproto) { uint8_t ipproto_map = FlowGetProtoMapping(ipproto); - return (alp_ctx.ctxs[ipproto_map][alproto].StateAlloc != NULL) ? 1 : 0; + return (alp_ctx.ctxs[alproto][ipproto_map].StateAlloc != NULL) ? 1 : 0; } AppLayerParserState *AppLayerParserStateAlloc(void) @@ -248,7 +248,12 @@ void AppLayerParserStateFree(AppLayerParserState *pstate) int AppLayerParserSetup(void) { SCEnter(); - memset(&alp_ctx, 0, sizeof(alp_ctx)); + // initial allocation that will later be grown using realloc, + // when new protocols register themselves and make AlprotoMax grow + alp_ctx.ctxs = SCCalloc(AlprotoMax, sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX])); + if (unlikely(alp_ctx.ctxs == NULL)) { + FatalError("Unable to alloc alp_ctx.ctxs."); + } SCReturnInt(0); } @@ -256,11 +261,10 @@ void AppLayerParserPostStreamSetup(void) { /* lets set a default value for stream_depth */ for (int flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { - if (!(alp_ctx.ctxs[flow_proto][alproto].internal_flags & + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { + if (!(alp_ctx.ctxs[alproto][flow_proto].internal_flags & APP_LAYER_PARSER_INT_STREAM_DEPTH_SET)) { - alp_ctx.ctxs[flow_proto][alproto].stream_depth = - stream_config.reassembly_depth; + alp_ctx.ctxs[alproto][flow_proto].stream_depth = stream_config.reassembly_depth; } } } @@ -270,6 +274,8 @@ int AppLayerParserDeSetup(void) { SCEnter(); + SCFree(alp_ctx.ctxs); + FTPParserCleanup(); SMTPParserCleanup(); @@ -284,12 +290,18 @@ AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void) if (tctx == NULL) goto end; + tctx->alproto_local_storage = SCCalloc(AlprotoMax, sizeof(void *[FLOW_PROTO_MAX])); + if (unlikely(tctx->alproto_local_storage == NULL)) { + SCFree(tctx); + tctx = NULL; + goto end; + } for (uint8_t flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); - tctx->alproto_local_storage[flow_proto][alproto] = - AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto); + tctx->alproto_local_storage[alproto][flow_proto] = + AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto); } } @@ -302,14 +314,15 @@ void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx) SCEnter(); for (uint8_t flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) { - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto); - AppLayerParserDestroyProtocolParserLocalStorage(ipproto, alproto, - tctx->alproto_local_storage[flow_proto][alproto]); + AppLayerParserDestroyProtocolParserLocalStorage( + ipproto, alproto, tctx->alproto_local_storage[alproto][flow_proto]); } } + SCFree(tctx->alproto_local_storage); SCFree(tctx); SCReturn; } @@ -381,8 +394,8 @@ int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)] + .Parser[(direction & STREAM_TOSERVER) ? 0 : 1] = Parser; SCReturnInt(0); } @@ -392,8 +405,8 @@ void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppPro { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].first_data_dir |= - (direction & (STREAM_TOSERVER | STREAM_TOCLIENT)); + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].first_data_dir |= + (direction & (STREAM_TOSERVER | STREAM_TOCLIENT)); SCReturn; } @@ -403,7 +416,7 @@ void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].option_flags |= flags; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].option_flags |= flags; SCReturn; } @@ -413,10 +426,8 @@ void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateAlloc = - StateAlloc; - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateFree = - StateFree; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateAlloc = StateAlloc; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateFree = StateFree; SCReturn; } @@ -427,10 +438,8 @@ void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageAlloc = - LocalStorageAlloc; - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].LocalStorageFree = - LocalStorageFree; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageAlloc = LocalStorageAlloc; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageFree = LocalStorageFree; SCReturn; } @@ -440,7 +449,7 @@ void AppLayerParserRegisterGetTxFilesFunc( { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxFiles = GetTxFiles; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxFiles = GetTxFiles; SCReturn; } @@ -449,7 +458,7 @@ void AppLayerParserRegisterLoggerBits(uint8_t ipproto, AppProto alproto, LoggerI { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].logger_bits = bits; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].logger_bits = bits; SCReturn; } @@ -458,7 +467,7 @@ void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].logger = true; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].logger = true; SCReturn; } @@ -468,8 +477,7 @@ void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alprot { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetProgress = StateGetProgress; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetProgress = StateGetProgress; SCReturn; } @@ -479,8 +487,7 @@ void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateTransactionFree = StateTransactionFree; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateTransactionFree = StateTransactionFree; SCReturn; } @@ -490,8 +497,7 @@ void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetTxCnt = StateGetTxCnt; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTxCnt = StateGetTxCnt; SCReturn; } @@ -501,8 +507,7 @@ void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetTx = StateGetTx; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTx = StateGetTx; SCReturn; } @@ -511,7 +516,7 @@ void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator = Func; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTxIterator = Func; SCReturn; } @@ -521,13 +526,13 @@ void AppLayerParserRegisterStateProgressCompletionStatus( BUG_ON(ts == 0); BUG_ON(tc == 0); BUG_ON(!AppProtoIsValid(alproto)); - BUG_ON(alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_ts != 0 && - alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_ts != ts); - BUG_ON(alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_tc != 0 && - alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_tc != tc); + BUG_ON(alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts != 0 && + alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts != ts); + BUG_ON(alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc != 0 && + alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc != tc); - alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_ts = ts; - alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_tc = tc; + alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts = ts; + alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc = tc; } void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, @@ -536,8 +541,8 @@ void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetEventInfoById = StateGetEventInfoById; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetEventInfoById = + StateGetEventInfoById; SCReturn; } @@ -547,8 +552,8 @@ void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetFrameNameByIdFn GetNameByIdFunc) { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetFrameIdByName = GetIdByNameFunc; - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetFrameNameById = GetNameByIdFunc; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameIdByName = GetIdByNameFunc; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameNameById = GetNameByIdFunc; SCReturn; } @@ -558,8 +563,7 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - StateGetEventInfo = StateGetEventInfo; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetEventInfo = StateGetEventInfo; SCReturn; } @@ -569,7 +573,7 @@ void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxData = GetTxData; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxData = GetTxData; SCReturn; } @@ -579,7 +583,7 @@ void AppLayerParserRegisterStateDataFunc( { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetStateData = GetStateData; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateData = GetStateData; SCReturn; } @@ -589,7 +593,7 @@ void AppLayerParserRegisterApplyTxConfigFunc(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].ApplyTxConfig = ApplyTxConfig; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].ApplyTxConfig = ApplyTxConfig; SCReturn; } @@ -599,7 +603,7 @@ void AppLayerParserRegisterSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetStreamDepthFlag = SetStreamDepthFlag; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].SetStreamDepthFlag = SetStreamDepthFlag; SCReturn; } @@ -611,11 +615,8 @@ void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alpr SCEnter(); void * r = NULL; - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageAlloc != NULL) - { - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageAlloc(); + if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageAlloc != NULL) { + r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageAlloc(); } SCReturnPtr(r, "void *"); @@ -626,11 +627,8 @@ void AppLayerParserDestroyProtocolParserLocalStorage(uint8_t ipproto, AppProto a { SCEnter(); - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageFree != NULL) - { - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto]. - LocalStorageFree(local_data); + if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageFree != NULL) { + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].LocalStorageFree(local_data); } SCReturn; @@ -675,7 +673,7 @@ AppLayerGetTxIteratorFunc AppLayerGetTxIterator(const uint8_t ipproto, const AppProto alproto) { AppLayerGetTxIteratorFunc Func = - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTxIterator; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTxIterator; return Func ? Func : AppLayerDefaultGetTxIterator; } @@ -855,8 +853,8 @@ AppLayerGetFileState AppLayerParserGetTxFiles(const Flow *f, void *tx, const uin { SCEnter(); - if (alp_ctx.ctxs[f->protomap][f->alproto].GetTxFiles != NULL) { - return alp_ctx.ctxs[f->protomap][f->alproto].GetTxFiles(tx, direction); + if (alp_ctx.ctxs[f->alproto][f->protomap].GetTxFiles != NULL) { + return alp_ctx.ctxs[f->alproto][f->protomap].GetTxFiles(tx, direction); } AppLayerGetFileState files = { .fc = NULL, .cfg = NULL }; @@ -886,7 +884,7 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) SCEnter(); DEBUG_ASSERT_FLOW_LOCKED(f); - AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][f->alproto]; + AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->alproto][f->protomap]; if (unlikely(p->StateTransactionFree == NULL)) SCReturn; @@ -1048,9 +1046,9 @@ void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir) static inline int StateGetProgressCompletionStatus(const AppProto alproto, const uint8_t flags) { if (flags & STREAM_TOSERVER) { - return alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_ts; + return alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_ts; } else if (flags & STREAM_TOCLIENT) { - return alp_ctx.ctxs[FLOW_PROTO_DEFAULT][alproto].complete_tc; + return alp_ctx.ctxs[alproto][FLOW_PROTO_DEFAULT].complete_tc; } else { DEBUG_VALIDATE_BUG_ON(1); return 0; @@ -1071,7 +1069,7 @@ int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, r = StateGetProgressCompletionStatus(alproto, flags); } else { uint8_t direction = flags & (STREAM_TOCLIENT | STREAM_TOSERVER); - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetProgress( + r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetProgress( alstate, direction); } SCReturnInt(r); @@ -1080,14 +1078,14 @@ int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate) { SCEnter(); - uint64_t r = alp_ctx.ctxs[f->protomap][f->alproto].StateGetTxCnt(alstate); + uint64_t r = alp_ctx.ctxs[f->alproto][f->protomap].StateGetTxCnt(alstate); SCReturnCT(r, "uint64_t"); } void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id) { SCEnter(); - void *r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateGetTx(alstate, tx_id); + void *r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateGetTx(alstate, tx_id); SCReturnPtr(r, "void *"); } @@ -1104,8 +1102,10 @@ int AppLayerParserGetEventInfo(uint8_t ipproto, AppProto alproto, const char *ev { SCEnter(); const int ipproto_map = FlowGetProtoMapping(ipproto); - int r = (alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo == NULL) ? - -1 : alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfo(event_name, event_id, event_type); + int r = (alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfo == NULL) + ? -1 + : alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfo( + event_name, event_id, event_type); SCReturnInt(r); } @@ -1115,15 +1115,17 @@ int AppLayerParserGetEventInfoById(uint8_t ipproto, AppProto alproto, uint8_t ev SCEnter(); const int ipproto_map = FlowGetProtoMapping(ipproto); *event_name = (const char *)NULL; - int r = (alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfoById == NULL) ? - -1 : alp_ctx.ctxs[ipproto_map][alproto].StateGetEventInfoById(event_id, event_name, event_type); + int r = (alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfoById == NULL) + ? -1 + : alp_ctx.ctxs[alproto][ipproto_map].StateGetEventInfoById( + event_id, event_name, event_type); SCReturnInt(r); } uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto) { SCEnter(); - uint8_t r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].first_data_dir; + uint8_t r = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].first_data_dir; SCReturnCT(r, "uint8_t"); } @@ -1135,7 +1137,7 @@ uint64_t AppLayerParserGetTransactionActive(const Flow *f, uint64_t active_id; uint64_t log_id = pstate->log_id; uint64_t inspect_id = pstate->inspect_id[(direction & STREAM_TOSERVER) ? 0 : 1]; - if (alp_ctx.ctxs[f->protomap][f->alproto].logger == true) { + if (alp_ctx.ctxs[f->alproto][f->protomap].logger == true) { active_id = MIN(log_id, inspect_id); } else { active_id = inspect_id; @@ -1151,22 +1153,22 @@ bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto) return AppLayerParserSupportsFiles(ipproto, ALPROTO_HTTP1) || AppLayerParserSupportsFiles(ipproto, ALPROTO_HTTP2); } - return alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxFiles != NULL; + return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxFiles != NULL; } AppLayerTxData *AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx) { SCEnter(); - AppLayerTxData *d = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxData(tx); + AppLayerTxData *d = alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetTxData(tx); SCReturnPtr(d, "AppLayerTxData"); } AppLayerStateData *AppLayerParserGetStateData(uint8_t ipproto, AppProto alproto, void *state) { SCEnter(); - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetStateData) { + if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateData) { AppLayerStateData *d = - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetStateData(state); + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetStateData(state); SCReturnPtr(d, "AppLayerStateData"); } SCReturnPtr(NULL, "AppLayerStateData"); @@ -1177,8 +1179,8 @@ void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, { SCEnter(); const int ipproto_map = FlowGetProtoMapping(ipproto); - if (alp_ctx.ctxs[ipproto_map][alproto].ApplyTxConfig) { - alp_ctx.ctxs[ipproto_map][alproto].ApplyTxConfig(state, tx, mode, config); + if (alp_ctx.ctxs[alproto][ipproto_map].ApplyTxConfig) { + alp_ctx.ctxs[alproto][ipproto_map].ApplyTxConfig(state, tx, mode, config); } SCReturn; } @@ -1270,7 +1272,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow BUG_ON(f->protomap != FlowGetProtoMapping(f->proto)); #endif AppLayerParserState *pstate = f->alparser; - AppLayerParserProtoCtx *p = &alp_ctx.ctxs[f->protomap][alproto]; + AppLayerParserProtoCtx *p = &alp_ctx.ctxs[alproto][f->protomap]; StreamSlice stream_slice; void *alstate = NULL; uint64_t p_tx_cnt = 0; @@ -1359,7 +1361,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow #endif /* invoke the parser */ AppLayerResult res = p->Parser[direction](f, alstate, pstate, stream_slice, - alp_tctx->alproto_local_storage[f->protomap][alproto]); + alp_tctx->alproto_local_storage[alproto][f->protomap]); if (res.status < 0) { AppLayerIncParserErrorCounter(tv, f); goto error; @@ -1505,7 +1507,7 @@ bool AppLayerParserHasDecoderEvents(AppLayerParserState *pstate) int AppLayerParserIsEnabled(AppProto alproto) { for (int i = 0; i < FLOW_PROTO_APPLAYER_MAX; i++) { - if (alp_ctx.ctxs[i][alproto].StateGetProgress != NULL) { + if (alp_ctx.ctxs[alproto][i].StateGetProgress != NULL) { return 1; } } @@ -1516,7 +1518,7 @@ int AppLayerParserProtocolHasLogger(uint8_t ipproto, AppProto alproto) { SCEnter(); int ipproto_map = FlowGetProtoMapping(ipproto); - int r = (alp_ctx.ctxs[ipproto_map][alproto].logger == false) ? 0 : 1; + int r = (alp_ctx.ctxs[alproto][ipproto_map].logger == false) ? 0 : 1; SCReturnInt(r); } @@ -1524,7 +1526,7 @@ LoggerId AppLayerParserProtocolGetLoggerBits(uint8_t ipproto, AppProto alproto) { SCEnter(); const int ipproto_map = FlowGetProtoMapping(ipproto); - LoggerId r = alp_ctx.ctxs[ipproto_map][alproto].logger_bits; + LoggerId r = alp_ctx.ctxs[alproto][ipproto_map].logger_bits; SCReturnUInt(r); } @@ -1543,16 +1545,16 @@ void AppLayerParserSetStreamDepth(uint8_t ipproto, AppProto alproto, uint32_t st { SCEnter(); - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].stream_depth = stream_depth; - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].internal_flags |= - APP_LAYER_PARSER_INT_STREAM_DEPTH_SET; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].stream_depth = stream_depth; + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].internal_flags |= + APP_LAYER_PARSER_INT_STREAM_DEPTH_SET; SCReturn; } uint32_t AppLayerParserGetStreamDepth(const Flow *f) { - SCReturnInt(alp_ctx.ctxs[f->protomap][f->alproto].stream_depth); + SCReturnInt(alp_ctx.ctxs[f->alproto][f->protomap].stream_depth); } void AppLayerParserSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *state, uint64_t tx_id, uint8_t flags) @@ -1561,8 +1563,8 @@ void AppLayerParserSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *s void *tx = NULL; if (state != NULL) { if ((tx = AppLayerParserGetTx(ipproto, alproto, state, tx_id)) != NULL) { - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetStreamDepthFlag != NULL) { - alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetStreamDepthFlag(tx, flags); + if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].SetStreamDepthFlag != NULL) { + alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].SetStreamDepthFlag(tx, flags); } } } @@ -1571,8 +1573,8 @@ void AppLayerParserSetStreamDepthFlag(uint8_t ipproto, AppProto alproto, void *s int AppLayerParserGetFrameIdByName(uint8_t ipproto, AppProto alproto, const char *name) { - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetFrameIdByName != NULL) { - return alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetFrameIdByName(name); + if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameIdByName != NULL) { + return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameIdByName(name); } else { return -1; } @@ -1580,8 +1582,8 @@ int AppLayerParserGetFrameIdByName(uint8_t ipproto, AppProto alproto, const char const char *AppLayerParserGetFrameNameById(uint8_t ipproto, AppProto alproto, const uint8_t id) { - if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetFrameNameById != NULL) { - return alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetFrameNameById(id); + if (alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameNameById != NULL) { + return alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].GetFrameNameById(id); } else { return NULL; } @@ -1594,7 +1596,7 @@ void AppLayerParserStateProtoCleanup( { SCEnter(); - AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[protomap][alproto]; + AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[alproto][protomap]; if (ctx->StateFree != NULL && alstate != NULL) ctx->StateFree(alstate); @@ -1614,7 +1616,7 @@ void AppLayerParserStateCleanup(const Flow *f, void *alstate, AppLayerParserStat static void ValidateParserProtoDump(AppProto alproto, uint8_t ipproto) { uint8_t map = FlowGetProtoMapping(ipproto); - const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[map][alproto]; + const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[alproto][map]; printf("ERROR: incomplete app-layer registration\n"); printf("AppLayer protocol %s ipproto %u\n", AppProtoToString(alproto), ipproto); printf("- option flags %"PRIx32"\n", ctx->option_flags); @@ -1640,7 +1642,7 @@ static void ValidateParserProtoDump(AppProto alproto, uint8_t ipproto) static void ValidateParserProto(AppProto alproto, uint8_t ipproto) { uint8_t map = FlowGetProtoMapping(ipproto); - const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[map][alproto]; + const AppLayerParserProtoCtx *ctx = &alp_ctx.ctxs[alproto][map]; if (ctx->Parser[0] == NULL && ctx->Parser[1] == NULL) return; @@ -1686,11 +1688,32 @@ static void ValidateParser(AppProto alproto) static void ValidateParsers(void) { AppProto p = 0; - for ( ; p < ALPROTO_MAX; p++) { + for (; p < AlprotoMax; p++) { ValidateParser(p); } } +#define ARRAY_CAP_STEP 16 +static void (**preregistered_callbacks)(void) = NULL; +static size_t preregistered_callbacks_nb = 0; +static size_t preregistered_callbacks_cap = 0; + +int AppLayerParserPreRegister(void (*Register)(void)) +{ + if (preregistered_callbacks_nb == preregistered_callbacks_cap) { + void *tmp = SCRealloc(preregistered_callbacks, + sizeof(void *) * (preregistered_callbacks_cap + ARRAY_CAP_STEP)); + if (tmp == NULL) { + return 1; + } + preregistered_callbacks_cap += ARRAY_CAP_STEP; + preregistered_callbacks = tmp; + } + preregistered_callbacks[preregistered_callbacks_nb] = Register; + preregistered_callbacks_nb++; + return 0; +} + void AppLayerParserRegisterProtocolParsers(void) { SCEnter(); @@ -1743,6 +1766,9 @@ void AppLayerParserRegisterProtocolParsers(void) } else { SCLogInfo("Protocol detection and parser disabled for pop3 protocol."); } + for (size_t i = 0; i < preregistered_callbacks_nb; i++) { + preregistered_callbacks[i](); + } ValidateParsers(); } @@ -1786,8 +1812,8 @@ void AppLayerParserRegisterUnittests(void) AppLayerParserProtoCtx *ctx; for (ip = 0; ip < FLOW_PROTO_DEFAULT; ip++) { - for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { - ctx = &alp_ctx.ctxs[ip][alproto]; + for (alproto = 0; alproto < AlprotoMax; alproto++) { + ctx = &alp_ctx.ctxs[alproto][ip]; if (ctx->RegisterUnittests == NULL) continue; ctx->RegisterUnittests(); diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 58ad4333563c..d233edf9eb1f 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -158,6 +158,7 @@ typedef AppLayerGetTxIterTuple (*AppLayerGetTxIteratorFunc) typedef int (*AppLayerParserGetFrameIdByNameFn)(const char *frame_name); typedef const char *(*AppLayerParserGetFrameNameByIdFn)(const uint8_t id); +int AppLayerParserPreRegister(void (*Register)(void)); /** * \brief Register app layer parser for the protocol. * diff --git a/src/app-layer-protos.c b/src/app-layer-protos.c index 03736554c7b6..710f698fc725 100644 --- a/src/app-layer-protos.c +++ b/src/app-layer-protos.c @@ -24,53 +24,18 @@ #include "suricata-common.h" #include "app-layer-protos.h" +#include "rust.h" + +AppProto AlprotoMax = ALPROTO_MAX_STATIC; +#define ARRAY_CAP_STEP 16 +AppProto AppProtoStringsCap = ALPROTO_MAX_STATIC; typedef struct AppProtoStringTuple { AppProto alproto; const char *str; } AppProtoStringTuple; -const AppProtoStringTuple AppProtoStrings[ALPROTO_MAX] = { - { ALPROTO_UNKNOWN, "unknown" }, - { ALPROTO_HTTP1, "http1" }, - { ALPROTO_FTP, "ftp" }, - { ALPROTO_SMTP, "smtp" }, - { ALPROTO_TLS, "tls" }, - { ALPROTO_SSH, "ssh" }, - { ALPROTO_IMAP, "imap" }, - { ALPROTO_JABBER, "jabber" }, - { ALPROTO_SMB, "smb" }, - { ALPROTO_DCERPC, "dcerpc" }, - { ALPROTO_IRC, "irc" }, - { ALPROTO_DNS, "dns" }, - { ALPROTO_MODBUS, "modbus" }, - { ALPROTO_ENIP, "enip" }, - { ALPROTO_DNP3, "dnp3" }, - { ALPROTO_NFS, "nfs" }, - { ALPROTO_NTP, "ntp" }, - { ALPROTO_FTPDATA, "ftp-data" }, - { ALPROTO_TFTP, "tftp" }, - { ALPROTO_IKE, "ike" }, - { ALPROTO_KRB5, "krb5" }, - { ALPROTO_QUIC, "quic" }, - { ALPROTO_DHCP, "dhcp" }, - { ALPROTO_SNMP, "snmp" }, - { ALPROTO_SIP, "sip" }, - { ALPROTO_RFB, "rfb" }, - { ALPROTO_MQTT, "mqtt" }, - { ALPROTO_PGSQL, "pgsql" }, - { ALPROTO_TELNET, "telnet" }, - { ALPROTO_WEBSOCKET, "websocket" }, - { ALPROTO_LDAP, "ldap" }, - { ALPROTO_DOH2, "doh2" }, - { ALPROTO_TEMPLATE, "template" }, - { ALPROTO_RDP, "rdp" }, - { ALPROTO_HTTP2, "http2" }, - { ALPROTO_BITTORRENT_DHT, "bittorrent-dht" }, - { ALPROTO_POP3, "pop3" }, - { ALPROTO_HTTP, "http" }, - { ALPROTO_FAILED, "failed" }, -}; +AppProtoStringTuple *AppProtoStrings = NULL; const char *AppProtoToString(AppProto alproto) { @@ -84,7 +49,7 @@ const char *AppProtoToString(AppProto alproto) proto_name = "http_any"; break; default: - if (alproto < ARRAY_SIZE(AppProtoStrings)) { + if (alproto < AlprotoMax) { BUG_ON(AppProtoStrings[alproto].alproto != alproto); proto_name = AppProtoStrings[alproto].str; } @@ -98,10 +63,35 @@ AppProto StringToAppProto(const char *proto_name) return ALPROTO_UNKNOWN; // We could use a Multi Pattern Matcher - for (size_t i = 0; i < ARRAY_SIZE(AppProtoStrings); i++) { + for (size_t i = 0; i < AlprotoMax; i++) { if (strcmp(proto_name, AppProtoStrings[i].str) == 0) return AppProtoStrings[i].alproto; } return ALPROTO_UNKNOWN; } + +void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name) +{ + if (alproto < ALPROTO_MAX_STATIC) { + if (AppProtoStrings == NULL) { + AppProtoStrings = SCCalloc(AppProtoStringsCap, sizeof(AppProtoStringTuple)); + if (AppProtoStrings == NULL) { + FatalError("Unable to allocate AppProtoStrings"); + } + } + } else if (alproto == AlprotoMax) { + if (AlprotoMax == AppProtoStringsCap) { + void *tmp = SCRealloc(AppProtoStrings, + sizeof(AppProtoStringTuple) * (AppProtoStringsCap + ARRAY_CAP_STEP)); + if (tmp == NULL) { + FatalError("Unable to reallocate AppProtoStrings"); + } + AppProtoStringsCap += ARRAY_CAP_STEP; + AppProtoStrings = tmp; + } + AlprotoMax++; + } + AppProtoStrings[alproto].str = proto_name; + AppProtoStrings[alproto].alproto = alproto; +} diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index 10b8959772c4..79942c8f6b70 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -27,6 +27,11 @@ enum AppProtoEnum { ALPROTO_UNKNOWN = 0, + /* used by the probing parser when alproto detection fails + * permanently for that particular stream */ + ALPROTO_FAILED = 1, + + // Beginning of real/normal protocols ALPROTO_HTTP1, ALPROTO_FTP, ALPROTO_SMTP, @@ -69,20 +74,18 @@ enum AppProtoEnum { // HTTP for any version (ALPROTO_HTTP1 (version 1) or ALPROTO_HTTP2) ALPROTO_HTTP, - /* used by the probing parser when alproto detection fails - * permanently for that particular stream */ - ALPROTO_FAILED, /* keep last */ - ALPROTO_MAX, + ALPROTO_MAX_STATIC, }; // NOTE: if ALPROTO's get >= 256, update SignatureNonPrefilterStore /* not using the enum as that is a unsigned int, so 4 bytes */ typedef uint16_t AppProto; +extern AppProto AlprotoMax; static inline bool AppProtoIsValid(AppProto a) { - return ((a > ALPROTO_UNKNOWN && a < ALPROTO_FAILED)); + return ((a > ALPROTO_FAILED && a < AlprotoMax)); } // whether a signature AppProto matches a flow (or signature) AppProto @@ -170,4 +173,6 @@ const char *AppProtoToString(AppProto alproto); */ AppProto StringToAppProto(const char *proto_name); +void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name); + #endif /* SURICATA_APP_LAYER_PROTOS_H */ diff --git a/src/app-layer-register.c b/src/app-layer-register.c index 1e4986b361ea..9a33a38eea76 100644 --- a/src/app-layer-register.c +++ b/src/app-layer-register.c @@ -101,7 +101,7 @@ int AppLayerRegisterParser(const struct AppLayerParser *p, AppProto alproto) if (p == NULL) FatalError("Call to %s with NULL pointer.", __FUNCTION__); - if (alproto == ALPROTO_UNKNOWN || alproto >= ALPROTO_FAILED) + if (!AppProtoIsValid(alproto)) FatalError("Unknown or invalid AppProto '%s'.", p->name); BUG_ON(strcmp(p->name, AppProtoToString(alproto)) != 0); diff --git a/src/app-layer.c b/src/app-layer.c index 9654c7d82e64..0a5be41173c4 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -96,9 +96,9 @@ typedef struct AppLayerCounters_ { } AppLayerCounters; /* counter names. Only used at init. */ -AppLayerCounterNames applayer_counter_names[FLOW_PROTO_APPLAYER_MAX][ALPROTO_MAX]; +AppLayerCounterNames (*applayer_counter_names)[FLOW_PROTO_APPLAYER_MAX]; /* counter id's. Used that runtime. */ -AppLayerCounters applayer_counters[FLOW_PROTO_APPLAYER_MAX][ALPROTO_MAX]; +AppLayerCounters (*applayer_counters)[FLOW_PROTO_APPLAYER_MAX]; /* Exception policy global counters ids */ ExceptionPolicyCounters eps_error_summary; @@ -145,7 +145,7 @@ static inline int ProtoDetectDone(const Flow *f, const TcpSession *ssn, uint8_t */ static void AppLayerIncFlowCounter(ThreadVars *tv, Flow *f) { - const uint16_t id = applayer_counters[f->protomap][f->alproto].counter_id; + const uint16_t id = applayer_counters[f->alproto][f->protomap].counter_id; if (likely(tv && id > 0)) { StatsIncr(tv, id); } @@ -153,7 +153,7 @@ static void AppLayerIncFlowCounter(ThreadVars *tv, Flow *f) void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) { - const uint16_t id = applayer_counters[f->protomap][f->alproto].counter_tx_id; + const uint16_t id = applayer_counters[f->alproto][f->protomap].counter_tx_id; if (likely(tv && id > 0)) { StatsAddUI64(tv, id, step); } @@ -161,7 +161,7 @@ void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) void AppLayerIncGapErrorCounter(ThreadVars *tv, Flow *f) { - const uint16_t id = applayer_counters[f->protomap][f->alproto].gap_error_id; + const uint16_t id = applayer_counters[f->alproto][f->protomap].gap_error_id; if (likely(tv && id > 0)) { StatsIncr(tv, id); } @@ -169,7 +169,7 @@ void AppLayerIncGapErrorCounter(ThreadVars *tv, Flow *f) void AppLayerIncAllocErrorCounter(ThreadVars *tv, Flow *f) { - const uint16_t id = applayer_counters[f->protomap][f->alproto].alloc_error_id; + const uint16_t id = applayer_counters[f->alproto][f->protomap].alloc_error_id; if (likely(tv && id > 0)) { StatsIncr(tv, id); } @@ -177,7 +177,7 @@ void AppLayerIncAllocErrorCounter(ThreadVars *tv, Flow *f) void AppLayerIncParserErrorCounter(ThreadVars *tv, Flow *f) { - const uint16_t id = applayer_counters[f->protomap][f->alproto].parser_error_id; + const uint16_t id = applayer_counters[f->alproto][f->protomap].parser_error_id; if (likely(tv && id > 0)) { StatsIncr(tv, id); } @@ -185,7 +185,7 @@ void AppLayerIncParserErrorCounter(ThreadVars *tv, Flow *f) void AppLayerIncInternalErrorCounter(ThreadVars *tv, Flow *f) { - const uint16_t id = applayer_counters[f->protomap][f->alproto].internal_error_id; + const uint16_t id = applayer_counters[f->alproto][f->protomap].internal_error_id; if (likely(tv && id > 0)) { StatsIncr(tv, id); } @@ -198,7 +198,7 @@ static void AppLayerIncrErrorExcPolicyCounter(ThreadVars *tv, Flow *f, enum Exce return; } #endif - uint16_t id = applayer_counters[f->protomap][f->alproto].eps_error.eps_id[policy]; + uint16_t id = applayer_counters[f->alproto][f->protomap].eps_error.eps_id[policy]; /* for the summary values */ uint16_t g_id = eps_error_summary.eps_id[policy]; @@ -1014,12 +1014,12 @@ void AppLayerListSupportedProtocols(void) SCEnter(); AppProto alproto; - AppProto alprotos[ALPROTO_MAX]; + AppProto alprotos[AlprotoMax]; AppLayerProtoDetectSupportedAppProtocols(alprotos); printf("=========Supported App Layer Protocols=========\n"); - for (alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (alproto = 0; alproto < AlprotoMax; alproto++) { if (alprotos[alproto] == 1) printf("%s\n", AppLayerGetProtoName(alproto)); } @@ -1028,11 +1028,54 @@ void AppLayerListSupportedProtocols(void) } /***** Setup/General Registration *****/ +static void AppLayerNamesSetup(void) +{ + AppProtoRegisterProtoString(ALPROTO_UNKNOWN, "unknown"); + AppProtoRegisterProtoString(ALPROTO_FAILED, "failed"); + AppProtoRegisterProtoString(ALPROTO_HTTP1, "http1"); + AppProtoRegisterProtoString(ALPROTO_FTP, "ftp"); + AppProtoRegisterProtoString(ALPROTO_SMTP, "smtp"); + AppProtoRegisterProtoString(ALPROTO_TLS, "tls"); + AppProtoRegisterProtoString(ALPROTO_SSH, "ssh"); + AppProtoRegisterProtoString(ALPROTO_IMAP, "imap"); + AppProtoRegisterProtoString(ALPROTO_JABBER, "jabber"); + AppProtoRegisterProtoString(ALPROTO_SMB, "smb"); + AppProtoRegisterProtoString(ALPROTO_DCERPC, "dcerpc"); + AppProtoRegisterProtoString(ALPROTO_IRC, "irc"); + AppProtoRegisterProtoString(ALPROTO_DNS, "dns"); + AppProtoRegisterProtoString(ALPROTO_MODBUS, "modbus"); + AppProtoRegisterProtoString(ALPROTO_ENIP, "enip"); + AppProtoRegisterProtoString(ALPROTO_DNP3, "dnp3"); + AppProtoRegisterProtoString(ALPROTO_NFS, "nfs"); + AppProtoRegisterProtoString(ALPROTO_NTP, "ntp"); + AppProtoRegisterProtoString(ALPROTO_FTPDATA, "ftp-data"); + AppProtoRegisterProtoString(ALPROTO_TFTP, "tftp"); + AppProtoRegisterProtoString(ALPROTO_IKE, "ike"); + AppProtoRegisterProtoString(ALPROTO_KRB5, "krb5"); + AppProtoRegisterProtoString(ALPROTO_QUIC, "quic"); + AppProtoRegisterProtoString(ALPROTO_DHCP, "dhcp"); + AppProtoRegisterProtoString(ALPROTO_SNMP, "snmp"); + AppProtoRegisterProtoString(ALPROTO_SIP, "sip"); + AppProtoRegisterProtoString(ALPROTO_RFB, "rfb"); + AppProtoRegisterProtoString(ALPROTO_MQTT, "mqtt"); + AppProtoRegisterProtoString(ALPROTO_PGSQL, "pgsql"); + AppProtoRegisterProtoString(ALPROTO_TELNET, "telnet"); + AppProtoRegisterProtoString(ALPROTO_WEBSOCKET, "websocket"); + AppProtoRegisterProtoString(ALPROTO_LDAP, "ldap"); + AppProtoRegisterProtoString(ALPROTO_DOH2, "doh2"); + AppProtoRegisterProtoString(ALPROTO_TEMPLATE, "template"); + AppProtoRegisterProtoString(ALPROTO_RDP, "rdp"); + AppProtoRegisterProtoString(ALPROTO_HTTP2, "http2"); + AppProtoRegisterProtoString(ALPROTO_BITTORRENT_DHT, "bittorrent-dht"); + AppProtoRegisterProtoString(ALPROTO_POP3, "pop3"); + AppProtoRegisterProtoString(ALPROTO_HTTP, "http"); +} int AppLayerSetup(void) { SCEnter(); + AppLayerNamesSetup(); AppLayerProtoDetectSetup(); AppLayerParserSetup(); @@ -1040,6 +1083,7 @@ int AppLayerSetup(void) AppLayerProtoDetectPrepareState(); AppLayerSetupCounters(); + FrameConfigInit(); SCReturnInt(0); } @@ -1052,6 +1096,7 @@ int AppLayerDeSetup(void) AppLayerParserDeSetup(); AppLayerDeSetupCounters(); + FrameConfigDeInit(); SCReturnInt(0); } @@ -1137,8 +1182,8 @@ static void AppLayerSetupExceptionPolicyPerProtoCounters( g_applayerparser_error_policy != EXCEPTION_POLICY_NOT_SET) { for (enum ExceptionPolicy i = EXCEPTION_POLICY_NOT_SET + 1; i < EXCEPTION_POLICY_MAX; i++) { if (IsAppLayerErrorExceptionPolicyStatsValid(i)) { - snprintf(applayer_counter_names[ipproto_map][alproto].eps_name[i], - sizeof(applayer_counter_names[ipproto_map][alproto].eps_name[i]), + snprintf(applayer_counter_names[alproto][ipproto_map].eps_name[i], + sizeof(applayer_counter_names[alproto][ipproto_map].eps_name[i]), "app_layer.error.%s%s.exception_policy.%s", alproto_str, ipproto_suffix, ExceptionPolicyEnumToString(i, true)); } @@ -1149,10 +1194,19 @@ static void AppLayerSetupExceptionPolicyPerProtoCounters( void AppLayerSetupCounters(void) { const uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; - AppProto alprotos[ALPROTO_MAX]; + AppProto alprotos[AlprotoMax]; const char *str = "app_layer.flow."; const char *estr = "app_layer.error."; + applayer_counter_names = + SCCalloc(AlprotoMax, sizeof(AppLayerCounterNames[FLOW_PROTO_APPLAYER_MAX])); + if (unlikely(applayer_counter_names == NULL)) { + FatalError("Unable to alloc applayer_counter_names."); + } + applayer_counters = SCCalloc(AlprotoMax, sizeof(AppLayerCounters[FLOW_PROTO_APPLAYER_MAX])); + if (unlikely(applayer_counters == NULL)) { + FatalError("Unable to alloc applayer_counters."); + } /* We don't log stats counters if exception policy is `ignore`/`not set` */ if (g_applayerparser_error_policy != EXCEPTION_POLICY_NOT_SET) { /* Register global counters for app layer error exception policy summary */ @@ -1174,7 +1228,7 @@ void AppLayerSetupCounters(void) const char *ipproto_suffix = (ipproto == IPPROTO_TCP) ? "_tcp" : "_udp"; uint8_t ipprotos_all[256 / 8]; - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { if (alprotos[alproto] == 1) { const char *tx_str = "app_layer.tx."; const char *alproto_str = AppLayerGetProtoName(alproto); @@ -1183,62 +1237,62 @@ void AppLayerSetupCounters(void) AppLayerProtoDetectSupportedIpprotos(alproto, ipprotos_all); if ((ipprotos_all[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) && (ipprotos_all[IPPROTO_UDP / 8] & (1 << (IPPROTO_UDP % 8)))) { - snprintf(applayer_counter_names[ipproto_map][alproto].name, - sizeof(applayer_counter_names[ipproto_map][alproto].name), - "%s%s%s", str, alproto_str, ipproto_suffix); - snprintf(applayer_counter_names[ipproto_map][alproto].tx_name, - sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), - "%s%s%s", tx_str, alproto_str, ipproto_suffix); + snprintf(applayer_counter_names[alproto][ipproto_map].name, + sizeof(applayer_counter_names[alproto][ipproto_map].name), "%s%s%s", + str, alproto_str, ipproto_suffix); + snprintf(applayer_counter_names[alproto][ipproto_map].tx_name, + sizeof(applayer_counter_names[alproto][ipproto_map].tx_name), "%s%s%s", + tx_str, alproto_str, ipproto_suffix); if (ipproto == IPPROTO_TCP) { - snprintf(applayer_counter_names[ipproto_map][alproto].gap_error, - sizeof(applayer_counter_names[ipproto_map][alproto].gap_error), + snprintf(applayer_counter_names[alproto][ipproto_map].gap_error, + sizeof(applayer_counter_names[alproto][ipproto_map].gap_error), "%s%s%s.gap", estr, alproto_str, ipproto_suffix); } - snprintf(applayer_counter_names[ipproto_map][alproto].alloc_error, - sizeof(applayer_counter_names[ipproto_map][alproto].alloc_error), + snprintf(applayer_counter_names[alproto][ipproto_map].alloc_error, + sizeof(applayer_counter_names[alproto][ipproto_map].alloc_error), "%s%s%s.alloc", estr, alproto_str, ipproto_suffix); - snprintf(applayer_counter_names[ipproto_map][alproto].parser_error, - sizeof(applayer_counter_names[ipproto_map][alproto].parser_error), + snprintf(applayer_counter_names[alproto][ipproto_map].parser_error, + sizeof(applayer_counter_names[alproto][ipproto_map].parser_error), "%s%s%s.parser", estr, alproto_str, ipproto_suffix); - snprintf(applayer_counter_names[ipproto_map][alproto].internal_error, - sizeof(applayer_counter_names[ipproto_map][alproto].internal_error), + snprintf(applayer_counter_names[alproto][ipproto_map].internal_error, + sizeof(applayer_counter_names[alproto][ipproto_map].internal_error), "%s%s%s.internal", estr, alproto_str, ipproto_suffix); AppLayerSetupExceptionPolicyPerProtoCounters( ipproto_map, alproto, alproto_str, ipproto_suffix); } else { - snprintf(applayer_counter_names[ipproto_map][alproto].name, - sizeof(applayer_counter_names[ipproto_map][alproto].name), - "%s%s", str, alproto_str); - snprintf(applayer_counter_names[ipproto_map][alproto].tx_name, - sizeof(applayer_counter_names[ipproto_map][alproto].tx_name), - "%s%s", tx_str, alproto_str); + snprintf(applayer_counter_names[alproto][ipproto_map].name, + sizeof(applayer_counter_names[alproto][ipproto_map].name), "%s%s", str, + alproto_str); + snprintf(applayer_counter_names[alproto][ipproto_map].tx_name, + sizeof(applayer_counter_names[alproto][ipproto_map].tx_name), "%s%s", + tx_str, alproto_str); if (ipproto == IPPROTO_TCP) { - snprintf(applayer_counter_names[ipproto_map][alproto].gap_error, - sizeof(applayer_counter_names[ipproto_map][alproto].gap_error), + snprintf(applayer_counter_names[alproto][ipproto_map].gap_error, + sizeof(applayer_counter_names[alproto][ipproto_map].gap_error), "%s%s.gap", estr, alproto_str); } - snprintf(applayer_counter_names[ipproto_map][alproto].alloc_error, - sizeof(applayer_counter_names[ipproto_map][alproto].alloc_error), + snprintf(applayer_counter_names[alproto][ipproto_map].alloc_error, + sizeof(applayer_counter_names[alproto][ipproto_map].alloc_error), "%s%s.alloc", estr, alproto_str); - snprintf(applayer_counter_names[ipproto_map][alproto].parser_error, - sizeof(applayer_counter_names[ipproto_map][alproto].parser_error), + snprintf(applayer_counter_names[alproto][ipproto_map].parser_error, + sizeof(applayer_counter_names[alproto][ipproto_map].parser_error), "%s%s.parser", estr, alproto_str); - snprintf(applayer_counter_names[ipproto_map][alproto].internal_error, - sizeof(applayer_counter_names[ipproto_map][alproto].internal_error), + snprintf(applayer_counter_names[alproto][ipproto_map].internal_error, + sizeof(applayer_counter_names[alproto][ipproto_map].internal_error), "%s%s.internal", estr, alproto_str); AppLayerSetupExceptionPolicyPerProtoCounters( ipproto_map, alproto, alproto_str, ""); } } else if (alproto == ALPROTO_FAILED) { - snprintf(applayer_counter_names[ipproto_map][alproto].name, - sizeof(applayer_counter_names[ipproto_map][alproto].name), - "%s%s%s", str, "failed", ipproto_suffix); + snprintf(applayer_counter_names[alproto][ipproto_map].name, + sizeof(applayer_counter_names[alproto][ipproto_map].name), "%s%s%s", str, + "failed", ipproto_suffix); if (ipproto == IPPROTO_TCP) { - snprintf(applayer_counter_names[ipproto_map][alproto].gap_error, - sizeof(applayer_counter_names[ipproto_map][alproto].gap_error), + snprintf(applayer_counter_names[alproto][ipproto_map].gap_error, + sizeof(applayer_counter_names[alproto][ipproto_map].gap_error), "%sfailed%s.gap", estr, ipproto_suffix); } } @@ -1249,7 +1303,7 @@ void AppLayerSetupCounters(void) void AppLayerRegisterThreadCounters(ThreadVars *tv) { const uint8_t ipprotos[] = { IPPROTO_TCP, IPPROTO_UDP }; - AppProto alprotos[ALPROTO_MAX]; + AppProto alprotos[AlprotoMax]; AppLayerProtoDetectSupportedAppProtocols(alprotos); /* We don't log stats counters if exception policy is `ignore`/`not set` */ @@ -1267,43 +1321,43 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) const uint8_t ipproto = ipprotos[p]; const uint8_t ipproto_map = FlowGetProtoMapping(ipproto); - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { if (alprotos[alproto] == 1) { - applayer_counters[ipproto_map][alproto].counter_id = - StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); + applayer_counters[alproto][ipproto_map].counter_id = + StatsRegisterCounter(applayer_counter_names[alproto][ipproto_map].name, tv); - applayer_counters[ipproto_map][alproto].counter_tx_id = - StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].tx_name, tv); + applayer_counters[alproto][ipproto_map].counter_tx_id = StatsRegisterCounter( + applayer_counter_names[alproto][ipproto_map].tx_name, tv); if (ipproto == IPPROTO_TCP) { - applayer_counters[ipproto_map][alproto].gap_error_id = StatsRegisterCounter( - applayer_counter_names[ipproto_map][alproto].gap_error, tv); + applayer_counters[alproto][ipproto_map].gap_error_id = StatsRegisterCounter( + applayer_counter_names[alproto][ipproto_map].gap_error, tv); } - applayer_counters[ipproto_map][alproto].alloc_error_id = StatsRegisterCounter( - applayer_counter_names[ipproto_map][alproto].alloc_error, tv); - applayer_counters[ipproto_map][alproto].parser_error_id = StatsRegisterCounter( - applayer_counter_names[ipproto_map][alproto].parser_error, tv); - applayer_counters[ipproto_map][alproto].internal_error_id = StatsRegisterCounter( - applayer_counter_names[ipproto_map][alproto].internal_error, tv); + applayer_counters[alproto][ipproto_map].alloc_error_id = StatsRegisterCounter( + applayer_counter_names[alproto][ipproto_map].alloc_error, tv); + applayer_counters[alproto][ipproto_map].parser_error_id = StatsRegisterCounter( + applayer_counter_names[alproto][ipproto_map].parser_error, tv); + applayer_counters[alproto][ipproto_map].internal_error_id = StatsRegisterCounter( + applayer_counter_names[alproto][ipproto_map].internal_error, tv); /* We don't log stats counters if exception policy is `ignore`/`not set` */ if (g_stats_eps_per_app_proto_errors && g_applayerparser_error_policy != EXCEPTION_POLICY_NOT_SET) { for (enum ExceptionPolicy i = EXCEPTION_POLICY_NOT_SET + 1; i < EXCEPTION_POLICY_MAX; i++) { if (IsAppLayerErrorExceptionPolicyStatsValid(i)) { - applayer_counters[ipproto_map][alproto] + applayer_counters[alproto][ipproto_map] .eps_error.eps_id[i] = StatsRegisterCounter( - applayer_counter_names[ipproto_map][alproto].eps_name[i], tv); + applayer_counter_names[alproto][ipproto_map].eps_name[i], tv); } } } } else if (alproto == ALPROTO_FAILED) { - applayer_counters[ipproto_map][alproto].counter_id = - StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv); + applayer_counters[alproto][ipproto_map].counter_id = + StatsRegisterCounter(applayer_counter_names[alproto][ipproto_map].name, tv); if (ipproto == IPPROTO_TCP) { - applayer_counters[ipproto_map][alproto].gap_error_id = StatsRegisterCounter( - applayer_counter_names[ipproto_map][alproto].gap_error, tv); + applayer_counters[alproto][ipproto_map].gap_error_id = StatsRegisterCounter( + applayer_counter_names[alproto][ipproto_map].gap_error, tv); } } } @@ -1312,8 +1366,8 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv) void AppLayerDeSetupCounters(void) { - memset(applayer_counter_names, 0, sizeof(applayer_counter_names)); - memset(applayer_counters, 0, sizeof(applayer_counters)); + SCFree(applayer_counter_names); + SCFree(applayer_counters); } /***** Unittests *****/ diff --git a/src/detect-engine-build.c b/src/detect-engine-build.c index c85f53d5051d..05ab4ff88dd8 100644 --- a/src/detect-engine-build.c +++ b/src/detect-engine-build.c @@ -625,10 +625,11 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG } mpm_stats[max_buffer_type_id]; memset(mpm_stats, 0x00, sizeof(mpm_stats)); - uint32_t alstats[ALPROTO_MAX] = {0}; + uint32_t alstats[AlprotoMax]; + memset(alstats, 0, AlprotoMax * sizeof(uint32_t)); uint32_t mpm_sizes[max_buffer_type_id][256]; memset(mpm_sizes, 0, sizeof(mpm_sizes)); - uint32_t alproto_mpm_bufs[ALPROTO_MAX][max_buffer_type_id]; + uint32_t alproto_mpm_bufs[AlprotoMax][max_buffer_type_id]; memset(alproto_mpm_bufs, 0, sizeof(alproto_mpm_bufs)); DEBUG_VALIDATE_BUG_ON(sgh->init == NULL); @@ -790,7 +791,7 @@ static json_t *RulesGroupPrintSghStats(const DetectEngineCtx *de_ctx, const SigG json_object_set_new(types, "any5", json_integer(any5_cnt)); json_object_set_new(stats, "types", types); - for (AppProto i = 0; i < ALPROTO_MAX; i++) { + for (AppProto i = 0; i < AlprotoMax; i++) { if (alstats[i] > 0) { json_t *app = json_object(); json_object_set_new(app, "total", json_integer(alstats[i])); diff --git a/src/detect-engine-file.h b/src/detect-engine-file.h index 13aa7465f436..10bcf5ca7dbc 100644 --- a/src/detect-engine-file.h +++ b/src/detect-engine-file.h @@ -28,4 +28,7 @@ uint8_t DetectFileInspectGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *_alstate, void *tx, uint64_t tx_id); +void DetectFileRegisterProto( + AppProto alproto, int direction, int to_client_progress, int to_server_progress); + #endif /* SURICATA_DETECT_ENGINE_FILE_H */ diff --git a/src/detect-engine-mpm.c b/src/detect-engine-mpm.c index 5e8687e34686..b1175b24915b 100644 --- a/src/detect-engine-mpm.c +++ b/src/detect-engine-mpm.c @@ -1972,7 +1972,7 @@ static void PrepareMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh) const int max_buffer_id = de_ctx->buffer_type_id + 1; const uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1; - AppProto engines[max_buffer_id][ALPROTO_MAX]; + AppProto engines[max_buffer_id][AlprotoMax]; memset(engines, 0, sizeof(engines)); int engines_idx[max_buffer_id]; memset(engines_idx, 0, sizeof(engines_idx)); diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index feff1251e4e2..fef89e7c66bf 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -521,7 +521,7 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) /* per alproto to set is_last_for_progress per alproto because the inspect * loop skips over engines that are not the correct alproto */ - for (AppProto a = 1; a < ALPROTO_FAILED; a++) { + for (AppProto a = ALPROTO_FAILED + 1; a < AlprotoMax; a++) { int last_tx_progress = 0; bool last_tx_progress_set = false; PrefilterEngine *prev_engine = NULL; diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 903cc158cf5f..7480e0c049b6 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -439,6 +439,27 @@ void SigTableCleanup(void) } } +#define ARRAY_CAP_STEP 16 +static void (**preregistered_callbacks)(void) = NULL; +static size_t preregistered_callbacks_nb = 0; +static size_t preregistered_callbacks_cap = 0; + +int SigTablePreRegister(void (*KeywordsRegister)(void)) +{ + if (preregistered_callbacks_nb == preregistered_callbacks_cap) { + void *tmp = SCRealloc(preregistered_callbacks, + sizeof(void *) * (preregistered_callbacks_cap + ARRAY_CAP_STEP)); + if (tmp == NULL) { + return 1; + } + preregistered_callbacks_cap += ARRAY_CAP_STEP; + preregistered_callbacks = tmp; + } + preregistered_callbacks[preregistered_callbacks_nb] = KeywordsRegister; + preregistered_callbacks_nb++; + return 0; +} + void SigTableInit(void) { if (sigmatch_table == NULL) { @@ -686,6 +707,10 @@ void SigTableSetup(void) ScDetectSipRegister(); ScDetectTemplateRegister(); + for (size_t i = 0; i < preregistered_callbacks_nb; i++) { + preregistered_callbacks[i](); + } + /* close keyword registration */ DetectBufferTypeCloseRegistration(); } diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index db4cd957af9d..671def0bd345 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -340,6 +340,7 @@ int SigTableList(const char *keyword); void SigTableCleanup(void); void SigTableInit(void); void SigTableSetup(void); +int SigTablePreRegister(void (*KeywordsRegister)(void)); void SigTableRegisterTests(void); #endif /* SURICATA_DETECT_ENGINE_REGISTER_H */ diff --git a/src/detect-engine.c b/src/detect-engine.c index 77c25a1cf3a9..d3d0ef527f14 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -181,7 +181,7 @@ static void AppLayerInspectEngineRegisterInternal(const char *name, AppProto alp } SCLogDebug("name %s id %d", name, sm_list); - if ((alproto >= ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || + if ((alproto == ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) || (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (progress < 0 || progress >= SHRT_MAX) || (Callback == NULL)) { SCLogError("Invalid arguments"); diff --git a/src/detect-file-data.c b/src/detect-file-data.c index a721c08c7cf9..90f305cc9013 100644 --- a/src/detect-file-data.c +++ b/src/detect-file-data.c @@ -97,11 +97,11 @@ static void SetupDetectEngineConfig(DetectEngineCtx *de_ctx) { if (de_ctx->filedata_config) return; - de_ctx->filedata_config = SCMalloc(ALPROTO_MAX * sizeof(DetectFileDataCfg)); + de_ctx->filedata_config = SCMalloc(AlprotoMax * sizeof(DetectFileDataCfg)); if (unlikely(de_ctx->filedata_config == NULL)) return; /* initialize default */ - for (AppProto i = 0; i < ALPROTO_MAX; i++) { + for (AppProto i = 0; i < AlprotoMax; i++) { de_ctx->filedata_config[i].content_limit = FILEDATA_CONTENT_LIMIT; de_ctx->filedata_config[i].content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE; } diff --git a/src/detect-parse.c b/src/detect-parse.c index 984501c1dd8a..7679a67382da 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -68,55 +68,80 @@ #include "string.h" #include "detect-parse.h" #include "detect-engine-iponly.h" +#include "detect-engine-file.h" #include "app-layer-detect-proto.h" #include "action-globals.h" #include "util-validate.h" +// file protocols with common file handling +typedef struct { + AppProto alproto; + int direction; + int to_client_progress; + int to_server_progress; +} DetectFileHandlerProtocol_t; + /* Table with all filehandler registrations */ DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE_STATIC]; +#define ALPROTO_WITHFILES_MAX 16 + +// file protocols with common file handling +DetectFileHandlerProtocol_t al_protocols[ALPROTO_WITHFILES_MAX] = { + { .alproto = ALPROTO_NFS, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .alproto = ALPROTO_SMB, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .alproto = ALPROTO_FTP, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .alproto = ALPROTO_FTPDATA, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, + { .alproto = ALPROTO_HTTP1, + .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, + .to_client_progress = HTP_RESPONSE_BODY, + .to_server_progress = HTP_REQUEST_BODY }, + { .alproto = ALPROTO_HTTP2, + .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, + .to_client_progress = HTTP2StateDataServer, + .to_server_progress = HTTP2StateDataClient }, + { .alproto = ALPROTO_SMTP, .direction = SIG_FLAG_TOSERVER }, { .alproto = ALPROTO_UNKNOWN } +}; + +void DetectFileRegisterProto( + AppProto alproto, int direction, int to_client_progress, int to_server_progress) +{ + size_t i = 0; + while (i < ALPROTO_WITHFILES_MAX && al_protocols[i].alproto != ALPROTO_UNKNOWN) { + i++; + } + if (i == ALPROTO_WITHFILES_MAX) { + return; + } + al_protocols[i].alproto = alproto; + al_protocols[i].direction = direction; + al_protocols[i].to_client_progress = to_client_progress; + al_protocols[i].to_server_progress = to_server_progress; + al_protocols[i + 1].alproto = ALPROTO_UNKNOWN; +} + void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg) { - // file protocols with common file handling - typedef struct { - AppProto al_proto; - int direction; - int to_client_progress; - int to_server_progress; - } DetectFileHandlerProtocol_t; - static DetectFileHandlerProtocol_t al_protocols[] = { - { .al_proto = ALPROTO_NFS, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_SMB, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_FTP, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_FTPDATA, .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT }, - { .al_proto = ALPROTO_HTTP1, - .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, - .to_client_progress = HTP_RESPONSE_BODY, - .to_server_progress = HTP_REQUEST_BODY }, - { .al_proto = ALPROTO_HTTP2, - .direction = SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, - .to_client_progress = HTTP2StateDataServer, - .to_server_progress = HTTP2StateDataClient }, - { .al_proto = ALPROTO_SMTP, .direction = SIG_FLAG_TOSERVER } - }; - - for (size_t i = 0; i < ARRAY_SIZE(al_protocols); i++) { + for (size_t i = 0; i < AlprotoMax; i++) { + if (al_protocols[i].alproto == ALPROTO_UNKNOWN) { + break; + } int direction = al_protocols[i].direction == 0 ? (int)(SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT) : al_protocols[i].direction; if (direction & SIG_FLAG_TOCLIENT) { DetectAppLayerMpmRegister(reg->name, SIG_FLAG_TOCLIENT, reg->priority, reg->PrefilterFn, - reg->GetData, al_protocols[i].al_proto, al_protocols[i].to_client_progress); - DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].al_proto, + reg->GetData, al_protocols[i].alproto, al_protocols[i].to_client_progress); + DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].alproto, SIG_FLAG_TOCLIENT, al_protocols[i].to_client_progress, reg->Callback, reg->GetData); } if (direction & SIG_FLAG_TOSERVER) { DetectAppLayerMpmRegister(reg->name, SIG_FLAG_TOSERVER, reg->priority, reg->PrefilterFn, - reg->GetData, al_protocols[i].al_proto, al_protocols[i].to_server_progress); - DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].al_proto, + reg->GetData, al_protocols[i].alproto, al_protocols[i].to_server_progress); + DetectAppLayerInspectEngineRegister(reg->name, al_protocols[i].alproto, SIG_FLAG_TOSERVER, al_protocols[i].to_server_progress, reg->Callback, reg->GetData); } @@ -1736,8 +1761,7 @@ int DetectSignatureAddTransform(Signature *s, int transform, void *options) int DetectSignatureSetAppProto(Signature *s, AppProto alproto) { - if (alproto == ALPROTO_UNKNOWN || - alproto >= ALPROTO_FAILED) { + if (!AppProtoIsValid(alproto)) { SCLogError("invalid alproto %u", alproto); return -1; } diff --git a/src/flow-private.h b/src/flow-private.h index bd7aac73644e..ebd4e11961b4 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -74,7 +74,7 @@ enum { FLOW_PROTO_MAX, }; /* max used in app-layer (counters) */ -#define FLOW_PROTO_APPLAYER_MAX FLOW_PROTO_UDP + 1 +#define FLOW_PROTO_APPLAYER_MAX (FLOW_PROTO_UDP + 1) /* * Variables diff --git a/src/output-tx.c b/src/output-tx.c index 40b887706770..3cf06d6b5935 100644 --- a/src/output-tx.c +++ b/src/output-tx.c @@ -67,7 +67,7 @@ int SCOutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto, Tx ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit) { if (list == NULL) { - list = SCCalloc(ALPROTO_MAX, sizeof(OutputTxLogger *)); + list = SCCalloc(AlprotoMax, sizeof(OutputTxLogger *)); if (unlikely(list == NULL)) { SCLogError("Failed to allocate OutputTx list"); return -1; @@ -542,14 +542,14 @@ static TmEcode OutputTxLog(ThreadVars *tv, Packet *p, void *thread_data) static TmEcode OutputTxLogThreadInit(ThreadVars *tv, const void *_initdata, void **data) { OutputTxLoggerThreadData *td = - SCCalloc(1, sizeof(*td) + ALPROTO_MAX * sizeof(OutputLoggerThreadStore *)); + SCCalloc(1, sizeof(*td) + AlprotoMax * sizeof(OutputLoggerThreadStore *)); if (td == NULL) return TM_ECODE_FAILED; *data = (void *)td; SCLogDebug("OutputTxLogThreadInit happy (*data %p)", *data); - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { OutputTxLogger *logger = list[alproto]; while (logger) { if (logger->ThreadInit) { @@ -598,7 +598,7 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) { OutputTxLoggerThreadData *op_thread_data = (OutputTxLoggerThreadData *)thread_data; - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { OutputLoggerThreadStore *store = op_thread_data->store[alproto]; OutputTxLogger *logger = list[alproto]; @@ -628,7 +628,7 @@ static TmEcode OutputTxLogThreadDeinit(ThreadVars *tv, void *thread_data) static uint32_t OutputTxLoggerGetActiveCount(void) { uint32_t cnt = 0; - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { for (OutputTxLogger *p = list[alproto]; p != NULL; p = p->next) { cnt++; } @@ -650,7 +650,7 @@ static uint32_t OutputTxLoggerGetActiveCount(void) void OutputTxLoggerRegister (void) { BUG_ON(list); - list = SCCalloc(ALPROTO_MAX, sizeof(OutputTxLogger *)); + list = SCCalloc(AlprotoMax, sizeof(OutputTxLogger *)); if (unlikely(list == NULL)) { FatalError("Failed to allocate OutputTx list"); } @@ -664,7 +664,7 @@ void OutputTxShutdown(void) if (list == NULL) { return; } - for (AppProto alproto = 0; alproto < ALPROTO_MAX; alproto++) { + for (AppProto alproto = 0; alproto < AlprotoMax; alproto++) { OutputTxLogger *logger = list[alproto]; while (logger) { OutputTxLogger *next_logger = logger->next; diff --git a/src/output.c b/src/output.c index b99897509c0f..d5b10c04cb21 100644 --- a/src/output.c +++ b/src/output.c @@ -835,7 +835,7 @@ void TmModuleLoggerRegister(void) EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto) { - if (alproto < ALPROTO_MAX) { + if (alproto < AlprotoMax) { return &simple_json_applayer_loggers[alproto]; } return NULL; @@ -857,7 +857,7 @@ static void RegisterSimpleJsonApplayerLogger( */ void OutputRegisterRootLoggers(void) { - simple_json_applayer_loggers = SCCalloc(ALPROTO_MAX, sizeof(EveJsonSimpleAppLayerLogger)); + simple_json_applayer_loggers = SCCalloc(AlprotoMax, sizeof(EveJsonSimpleAppLayerLogger)); if (unlikely(simple_json_applayer_loggers == NULL)) { FatalError("Failed to allocate simple_json_applayer_loggers"); } @@ -949,6 +949,28 @@ static int JsonGenericDirFlowLogger(ThreadVars *tv, void *thread_data, const Pac return JsonGenericLogger(tv, thread_data, p, f, state, tx, tx_id, LOG_DIR_FLOW); } +#define ARRAY_CAP_STEP 16 +static EveJsonLoggerRegistrationData *preregistered_loggers = NULL; +static size_t preregistered_loggers_nb = 0; +static size_t preregistered_loggers_cap = 0; + +int OutputPreRegisterLogger(EveJsonLoggerRegistrationData reg_data) +{ + if (preregistered_loggers_nb == preregistered_loggers_cap) { + void *tmp = SCRealloc( + preregistered_loggers, sizeof(EveJsonLoggerRegistrationData) * + (preregistered_loggers_cap + ARRAY_CAP_STEP)); + if (tmp == NULL) { + return 1; + } + preregistered_loggers_cap += ARRAY_CAP_STEP; + preregistered_loggers = tmp; + } + preregistered_loggers[preregistered_loggers_nb] = reg_data; + preregistered_loggers_nb++; + return 0; +} + /** * \brief Register all non-root logging modules. */ @@ -1105,4 +1127,15 @@ void OutputRegisterLoggers(void) } /* ARP JSON logger */ JsonArpLogRegister(); + + for (size_t i = 0; i < preregistered_loggers_nb; i++) { + OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", preregistered_loggers[i].logname, + preregistered_loggers[i].confname, OutputJsonLogInitSub, + preregistered_loggers[i].alproto, JsonGenericDirFlowLogger, JsonLogThreadInit, + JsonLogThreadDeinit); + SCLogNotice( + "%s JSON logger registered.", AppProtoToString(preregistered_loggers[i].alproto)); + RegisterSimpleJsonApplayerLogger( + preregistered_loggers[i].alproto, preregistered_loggers[i].LogTx, NULL); + } } diff --git a/src/output.h b/src/output.h index 43bd9d8b8f74..3820ae1665d8 100644 --- a/src/output.h +++ b/src/output.h @@ -170,4 +170,13 @@ typedef struct EveJsonSimpleAppLayerLogger { EveJsonSimpleAppLayerLogger *SCEveJsonSimpleGetLogger(AppProto alproto); +typedef struct EveJsonLoggerRegistrationData { + const char *confname; + const char *logname; + AppProto alproto; + EveJsonSimpleTxLogFunc LogTx; +} EveJsonLoggerRegistrationData; + +int OutputPreRegisterLogger(EveJsonLoggerRegistrationData reg_data); + #endif /* ! SURICATA_OUTPUT_H */ diff --git a/src/runmodes.c b/src/runmodes.c index b326a96e3a67..0306fd6a1a01 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -757,8 +757,9 @@ void RunModeInitializeOutputs(void) char tls_log_enabled = 0; char tls_store_present = 0; - // ALPROTO_MAX is set to its final value - LoggerId logger_bits[ALPROTO_MAX] = { 0 }; + // AlprotoMax is set to its final value + LoggerId logger_bits[AlprotoMax]; + memset(logger_bits, 0, AlprotoMax * sizeof(LoggerId)); TAILQ_FOREACH(output, &outputs->head, next) { output_config = ConfNodeLookupChild(output, output->val); @@ -884,7 +885,7 @@ void RunModeInitializeOutputs(void) /* register the logger bits to the app-layer */ AppProto a; - for (a = 0; a < ALPROTO_MAX; a++) { + for (a = 0; a < AlprotoMax; a++) { if (AppLayerParserSupportsFiles(IPPROTO_TCP, a)) { if (g_file_logger_enabled) logger_bits[a] |= BIT_U32(LOGGER_FILE); @@ -919,7 +920,6 @@ void RunModeInitializeOutputs(void) AppLayerParserRegisterLoggerBits(IPPROTO_TCP, a, logger_bits[a]); if (udp) AppLayerParserRegisterLoggerBits(IPPROTO_UDP, a, logger_bits[a]); - } OutputSetupActiveLoggers(); } diff --git a/src/suricata-plugin.h b/src/suricata-plugin.h index 639dd7c7313e..8bc2183d70fd 100644 --- a/src/suricata-plugin.h +++ b/src/suricata-plugin.h @@ -52,4 +52,20 @@ typedef struct SCCapturePlugin_ { int SCPluginRegisterCapture(SCCapturePlugin *); +// Every change in the API used by plugins should change this number +#define SC_PLUGIN_API_VERSION 8 + +typedef struct SCAppLayerPlugin_ { + // versioning to check suricata/plugin API compatibility + uint64_t version; + char *name; + void (*Register)(void); + void (*KeywordsRegister)(void); + char *logname; + char *confname; + bool (*Logger)(void *tx, void *jb); +} SCAppLayerPlugin; + +int SCPluginRegisterAppLayer(SCAppLayerPlugin *); + #endif /* __SURICATA_PLUGIN_H */ diff --git a/src/suricata.c b/src/suricata.c index ee9dfc0b5b69..6a01b55dd3ca 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -361,7 +361,6 @@ void GlobalsInitPreConfig(void) SupportFastPatternForSigMatchTypes(); SCThresholdConfGlobalInit(); SCProtoNameInit(); - FrameConfigInit(); } void GlobalsDestroy(void) diff --git a/src/tests/fuzz/fuzz_applayerparserparse.c b/src/tests/fuzz/fuzz_applayerparserparse.c index f20c566e399a..bd2ecfae6ddb 100644 --- a/src/tests/fuzz/fuzz_applayerparserparse.c +++ b/src/tests/fuzz/fuzz_applayerparserparse.c @@ -36,32 +36,15 @@ extern const char *configNoChecksum; const uint8_t separator[] = {0x01, 0xD5, 0xCA, 0x7A}; SCInstance surifuzz; AppProto forceLayer = 0; +char *target_suffix = NULL; SC_ATOMIC_EXTERN(unsigned int, engine_stage); int LLVMFuzzerInitialize(int *argc, char ***argv) { - char *target_suffix = strrchr((*argv)[0], '_'); - if (target_suffix != NULL) { - AppProto applayer = StringToAppProto(target_suffix + 1); - if (applayer != ALPROTO_UNKNOWN) { - forceLayer = applayer; - printf("Forcing %s=%" PRIu16 "\n", AppProtoToString(forceLayer), forceLayer); - return 0; - } - } + target_suffix = strrchr((*argv)[0], '_'); // else - const char *forceLayerStr = getenv("FUZZ_APPLAYER"); - if (forceLayerStr) { - if (ByteExtractStringUint16(&forceLayer, 10, 0, forceLayerStr) < 0) { - forceLayer = 0; - printf("Invalid numeric value for FUZZ_APPLAYER environment variable"); - } else { - printf("Forcing %s\n", AppProtoToString(forceLayer)); - } - } - // http is the output name, but we want to fuzz HTTP1 - if (forceLayer == ALPROTO_HTTP) { - forceLayer = ALPROTO_HTTP1; + if (!target_suffix) { + target_suffix = getenv("FUZZ_APPLAYER"); } return 0; } @@ -96,13 +79,24 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) PostConfLoadedSetup(&surifuzz); alp_tctx = AppLayerParserThreadCtxAlloc(); SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME); + if (target_suffix != NULL) { + AppProto applayer = StringToAppProto(target_suffix + 1); + if (applayer != ALPROTO_UNKNOWN) { + forceLayer = applayer; + printf("Forcing %s=%" PRIu16 "\n", AppProtoToString(forceLayer), forceLayer); + } + } + // http is the output name, but we want to fuzz HTTP1 + if (forceLayer == ALPROTO_HTTP) { + forceLayer = ALPROTO_HTTP1; + } } if (size < HEADER_LEN) { return 0; } - if (data[0] >= ALPROTO_MAX) { + if (data[0] >= AlprotoMax) { return 0; } //no UTHBuildFlow to have storage diff --git a/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c b/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c index e30f729bc28f..4473de00941c 100644 --- a/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c +++ b/src/tests/fuzz/fuzz_applayerprotodetectgetproto.c @@ -9,7 +9,7 @@ #include "suricata.h" #include "app-layer-detect-proto.h" #include "flow-util.h" -#include "app-layer-parser.h" +#include "app-layer.h" #include "util-unittest-helper.h" #include "conf-yaml-loader.h" @@ -30,8 +30,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) Flow *f; TcpSession ssn; bool reverse; - AppProto alproto; - AppProto alproto2; if (alpd_tctx == NULL) { //global init @@ -43,9 +41,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) MpmTableSetup(); SpmTableSetup(); EngineModeSetIDS(); - AppLayerProtoDetectSetup(); - AppLayerParserSetup(); - AppLayerParserRegisterProtocolParsers(); + AppLayerSetup(); alpd_tctx = AppLayerProtoDetectGetCtxThread(); SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME); } @@ -68,31 +64,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (data[0] & STREAM_TOSERVER) { flags = STREAM_TOSERVER; } - alproto = AppLayerProtoDetectGetProto( + AppLayerProtoDetectGetProto( alpd_tctx, f, data + HEADER_LEN, size - HEADER_LEN, f->proto, flags, &reverse); - if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED && f->proto == IPPROTO_TCP) { - /* If we find a valid protocol at the start of a stream : - * check that with smaller input - * we find the same protocol or ALPROTO_UNKNOWN. - * Otherwise, we have evasion with TCP splitting - */ - for (size_t i = 0; i < size-HEADER_LEN && i < PROTO_DETECT_MAX_LEN; i++) { - // reset detection at each try cf probing_parser_toserver_alproto_masks - AppLayerProtoDetectReset(f); - alproto2 = AppLayerProtoDetectGetProto( - alpd_tctx, f, data + HEADER_LEN, i, f->proto, flags, &reverse); - if (alproto2 != ALPROTO_UNKNOWN && alproto2 != alproto) { - printf("Failed with input length %" PRIuMAX " versus %" PRIuMAX - ", found %s instead of %s\n", - (uintmax_t)i, (uintmax_t)size - HEADER_LEN, AppProtoToString(alproto2), - AppProtoToString(alproto)); - printf("Assertion failure: %s-%s\n", AppProtoToString(alproto2), - AppProtoToString(alproto)); - fflush(stdout); - abort(); - } - } - } FlowFree(f); return 0; diff --git a/src/util-exception-policy-types.h b/src/util-exception-policy-types.h index b5295d19305b..a6139acc8934 100644 --- a/src/util-exception-policy-types.h +++ b/src/util-exception-policy-types.h @@ -33,7 +33,7 @@ enum ExceptionPolicy { EXCEPTION_POLICY_REJECT, }; -#define EXCEPTION_POLICY_MAX EXCEPTION_POLICY_REJECT + 1 +#define EXCEPTION_POLICY_MAX (EXCEPTION_POLICY_REJECT + 1) /* Max length = possible exception policy scenarios + counter names * + exception policy type. E.g.: diff --git a/src/util-plugin.c b/src/util-plugin.c index 7a9b467daaac..ebcaeace9dd3 100644 --- a/src/util-plugin.c +++ b/src/util-plugin.c @@ -25,6 +25,11 @@ #ifdef HAVE_PLUGINS +#include "app-layer-protos.h" +#include "app-layer-parser.h" +#include "detect-engine-register.h" +#include "output.h" + #include typedef struct PluginListNode_ { @@ -148,4 +153,35 @@ SCCapturePlugin *SCPluginFindCaptureByName(const char *name) } return plugin; } + +int SCPluginRegisterAppLayer(SCAppLayerPlugin *plugin) +{ + if (plugin->version != SC_PLUGIN_API_VERSION) { + return 1; + } + AppProto alproto = AlprotoMax; + AppProtoRegisterProtoString(alproto, plugin->name); + if (plugin->Register) { + if (AppLayerParserPreRegister(plugin->Register) != 0) { + return 1; + } + } + if (plugin->KeywordsRegister) { + if (SigTablePreRegister(plugin->KeywordsRegister) != 0) { + return 1; + } + } + if (plugin->Logger) { + EveJsonLoggerRegistrationData reg_data = { + .confname = plugin->confname, + .logname = plugin->logname, + .alproto = alproto, + .LogTx = (EveJsonSimpleTxLogFunc)plugin->Logger, + }; + if (OutputPreRegisterLogger(reg_data) != 0) { + return 1; + } + } + return 0; +} #endif diff --git a/src/util-profiling.c b/src/util-profiling.c index 80d3938bd41f..04ff786f726c 100644 --- a/src/util-profiling.c +++ b/src/util-profiling.c @@ -72,8 +72,8 @@ SCProfilePacketData packet_profile_data6[257]; /**< all proto's + tunnel */ SCProfilePacketData packet_profile_tmm_data4[TMM_SIZE][257]; SCProfilePacketData packet_profile_tmm_data6[TMM_SIZE][257]; -SCProfilePacketData packet_profile_app_data4[ALPROTO_MAX][257]; -SCProfilePacketData packet_profile_app_data6[ALPROTO_MAX][257]; +SCProfilePacketData *packet_profile_app_data4; +SCProfilePacketData *packet_profile_app_data6; SCProfilePacketData packet_profile_app_pd_data4[257]; SCProfilePacketData packet_profile_app_pd_data6[257]; @@ -158,8 +158,14 @@ SCProfilingInit(void) memset(&packet_profile_data6, 0, sizeof(packet_profile_data6)); memset(&packet_profile_tmm_data4, 0, sizeof(packet_profile_tmm_data4)); memset(&packet_profile_tmm_data6, 0, sizeof(packet_profile_tmm_data6)); - memset(&packet_profile_app_data4, 0, sizeof(packet_profile_app_data4)); - memset(&packet_profile_app_data6, 0, sizeof(packet_profile_app_data6)); + packet_profile_app_data4 = SCCalloc(AlprotoMax * 257, sizeof(SCProfilePacketData)); + if (packet_profile_app_data4 == NULL) { + FatalError("Failed to allocate packet_profile_app_data4"); + } + packet_profile_app_data6 = SCCalloc(AlprotoMax * 257, sizeof(SCProfilePacketData)); + if (packet_profile_app_data6 == NULL) { + FatalError("Failed to allocate packet_profile_app_data6"); + } memset(&packet_profile_app_pd_data4, 0, sizeof(packet_profile_app_pd_data4)); memset(&packet_profile_app_pd_data6, 0, sizeof(packet_profile_app_pd_data6)); memset(&packet_profile_detect_data4, 0, sizeof(packet_profile_detect_data4)); @@ -269,6 +275,15 @@ SCProfilingInit(void) void SCProfilingDestroy(void) { + if (packet_profile_app_data4) { + SCFree(packet_profile_app_data4); + packet_profile_app_data4 = NULL; + } + if (packet_profile_app_data6) { + SCFree(packet_profile_app_data6); + packet_profile_app_data6 = NULL; + } + if (profiling_packets_enabled) { pthread_mutex_destroy(&packet_profile_lock); } @@ -488,18 +503,18 @@ void SCProfilingDumpPacketStats(void) "--------------------", "------", "-----", "----------", "------------", "------------", "-----------"); total = 0; - for (AppProto a = 0; a < ALPROTO_MAX; a++) { + for (AppProto a = 0; a < AlprotoMax; a++) { for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_data4[a][p]; + SCProfilePacketData *pd = &packet_profile_app_data4[a * 257 + p]; total += pd->tot; - pd = &packet_profile_app_data6[a][p]; + pd = &packet_profile_app_data6[a * 257 + p]; total += pd->tot; } } - for (AppProto a = 0; a < ALPROTO_MAX; a++) { + for (AppProto a = 0; a < AlprotoMax; a++) { for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_data4[a][p]; + SCProfilePacketData *pd = &packet_profile_app_data4[a * 257 + p]; if (pd->cnt == 0) { continue; } @@ -516,9 +531,9 @@ void SCProfilingDumpPacketStats(void) } } - for (AppProto a = 0; a < ALPROTO_MAX; a++) { + for (AppProto a = 0; a < AlprotoMax; a++) { for (int p = 0; p < 257; p++) { - SCProfilePacketData *pd = &packet_profile_app_data6[a][p]; + SCProfilePacketData *pd = &packet_profile_app_data6[a * 257 + p]; if (pd->cnt == 0) { continue; } @@ -805,7 +820,7 @@ void SCProfilingPrintPacketProfile(Packet *p) /* count ticks for app layer */ uint64_t app_total = 0; - for (AppProto i = 1; i < ALPROTO_FAILED; i++) { + for (AppProto i = 0; i < AlprotoMax; i++) { const PktProfilingAppData *pdt = &p->profile->app[i]; if (p->proto == IPPROTO_TCP) { @@ -918,9 +933,9 @@ static void SCProfilingUpdatePacketAppRecord(int alproto, uint8_t ipproto, PktPr SCProfilePacketData *pd; if (ipver == 4) - pd = &packet_profile_app_data4[alproto][ipproto]; + pd = &packet_profile_app_data4[alproto * 257 + ipproto]; else - pd = &packet_profile_app_data6[alproto][ipproto]; + pd = &packet_profile_app_data6[alproto * 257 + ipproto]; if (pd->min == 0 || pdt->ticks_spent < pd->min) { pd->min = pdt->ticks_spent; @@ -936,7 +951,7 @@ static void SCProfilingUpdatePacketAppRecord(int alproto, uint8_t ipproto, PktPr static void SCProfilingUpdatePacketAppRecords(Packet *p) { int i; - for (i = 0; i < ALPROTO_MAX; i++) { + for (i = 0; i < AlprotoMax; i++) { PktProfilingAppData *pdt = &p->profile->app[i]; if (pdt->ticks_spent > 0) { @@ -1184,7 +1199,7 @@ PktProfiling *SCProfilePacketStart(void) { uint64_t sample = SC_ATOMIC_ADD(samples, 1); if (sample % rate == 0) - return SCCalloc(1, sizeof(PktProfiling) + ALPROTO_MAX * sizeof(PktProfilingAppData)); + return SCCalloc(1, sizeof(PktProfiling) + AlprotoMax * sizeof(PktProfilingAppData)); return NULL; } diff --git a/src/util-profiling.h b/src/util-profiling.h index 1c334bb34f27..284adcced795 100644 --- a/src/util-profiling.h +++ b/src/util-profiling.h @@ -203,12 +203,12 @@ PktProfiling *SCProfilePacketStart(void); (dp)->proto_detect_ticks_spent = 0; \ } -#define PACKET_PROFILING_APP_STORE(dp, p) \ - if (profiling_packets_enabled && (p)->profile != NULL) { \ - if ((dp)->alproto < ALPROTO_MAX) { \ - (p)->profile->app[(dp)->alproto].ticks_spent += (dp)->ticks_spent; \ - (p)->profile->proto_detect += (dp)->proto_detect_ticks_spent; \ - } \ +#define PACKET_PROFILING_APP_STORE(dp, p) \ + if (profiling_packets_enabled && (p)->profile != NULL) { \ + if ((dp)->alproto < AlprotoMax) { \ + (p)->profile->app[(dp)->alproto].ticks_spent += (dp)->ticks_spent; \ + (p)->profile->proto_detect += (dp)->proto_detect_ticks_spent; \ + } \ } #define PACKET_PROFILING_DETECT_START(p, id) \